arkon 5 роки тому
батько
коміт
3f63b320c4
100 змінених файлів з 2115 додано та 1874 видалено
  1. 4 4
      app/src/main/java/eu/kanade/tachiyomi/App.kt
  2. 0 1
      app/src/main/java/eu/kanade/tachiyomi/AppModule.kt
  3. 6 5
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt
  4. 26 24
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt
  5. 141 132
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt
  6. 8 5
      app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt
  7. 3 2
      app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt
  8. 11 11
      app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt
  9. 4 2
      app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt
  10. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt
  11. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt
  12. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt
  13. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt
  14. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt
  15. 13 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt
  16. 16 12
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt
  17. 58 48
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt
  18. 48 38
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt
  19. 8 6
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt
  20. 97 77
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt
  21. 18 9
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt
  22. 17 13
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt
  23. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt
  24. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt
  25. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt
  26. 8 6
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt
  27. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt
  28. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt
  29. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt
  30. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt
  31. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt
  32. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt
  33. 3 2
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt
  34. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt
  35. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt
  36. 3 2
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt
  37. 2 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt
  38. 12 12
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt
  39. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
  40. 20 12
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt
  41. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt
  42. 11 7
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt
  43. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt
  44. 96 90
      app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt
  45. 17 17
      app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt
  46. 28 25
      app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt
  47. 9 4
      app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt
  48. 13 11
      app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt
  49. 5 4
      app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt
  50. 184 154
      app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
  51. 38 25
      app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt
  52. 30 18
      app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt
  53. 15 7
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
  54. 1 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt
  55. 16 16
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt
  56. 109 97
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt
  57. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt
  58. 26 26
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt
  59. 103 93
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt
  60. 16 13
      app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt
  61. 20 20
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt
  62. 91 89
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt
  63. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt
  64. 23 22
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt
  65. 177 172
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt
  66. 1 1
      app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt
  67. 17 17
      app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt
  68. 88 85
      app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt
  69. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt
  70. 14 11
      app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt
  71. 20 12
      app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt
  72. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt
  73. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt
  74. 16 16
      app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt
  75. 6 3
      app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt
  76. 16 16
      app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt
  77. 3 3
      app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt
  78. 2 2
      app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt
  79. 37 37
      app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt
  80. 27 24
      app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt
  81. 3 3
      app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt
  82. 4 4
      app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt
  83. 6 6
      app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt
  84. 8 8
      app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt
  85. 9 9
      app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt
  86. 4 4
      app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt
  87. 51 47
      app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt
  88. 1 1
      app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt
  89. 12 6
      app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt
  90. 31 29
      app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt
  91. 8 8
      app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt
  92. 11 9
      app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt
  93. 3 2
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt
  94. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt
  95. 4 2
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt
  96. 0 8
      app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt
  97. 5 5
      app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt
  98. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt
  99. 13 10
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt
  100. 11 11
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/App.kt

@@ -23,12 +23,12 @@ import uy.kohesive.injekt.injectLazy
 import uy.kohesive.injekt.registry.default.DefaultRegistrar
 
 @AcraCore(
-        buildConfigClass = BuildConfig::class,
-        excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"]
+    buildConfigClass = BuildConfig::class,
+    excludeMatchingSharedPreferencesKeys = [".*username.*", ".*password.*", ".*token.*"]
 )
 @AcraHttpSender(
-        uri = "https://tachiyomi.kanade.eu/crash_report",
-        httpMethod = HttpSender.Method.PUT
+    uri = "https://tachiyomi.kanade.eu/crash_report",
+    httpMethod = HttpSender.Method.PUT
 )
 open class App : Application(), LifecycleObserver {
 

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/AppModule.kt

@@ -22,7 +22,6 @@ import uy.kohesive.injekt.api.get
 class AppModule(val app: Application) : InjektModule {
 
     override fun InjektRegistrar.registerInjectables() {
-
         addSingleton(app)
 
         addSingletonFactory { PreferencesHelper(app) }

+ 6 - 5
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt

@@ -13,7 +13,7 @@ import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
 class BackupCreatorJob(private val context: Context, workerParams: WorkerParameters) :
-        Worker(context, workerParams) {
+    Worker(context, workerParams) {
 
     override fun doWork(): Result {
         val preferences = Injekt.get<PreferencesHelper>()
@@ -32,10 +32,11 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet
             val interval = prefInterval ?: preferences.backupInterval().get()
             if (interval > 0) {
                 val request = PeriodicWorkRequestBuilder<BackupCreatorJob>(
-                        interval.toLong(), TimeUnit.HOURS,
-                        10, TimeUnit.MINUTES)
-                        .addTag(TAG)
-                        .build()
+                    interval.toLong(), TimeUnit.HOURS,
+                    10, TimeUnit.MINUTES
+                )
+                    .addTag(TAG)
+                    .build()
 
                 WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request)
             } else {

+ 26 - 24
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt

@@ -85,7 +85,8 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
 
     private fun initParser(): Gson = when (version) {
         1 -> GsonBuilder().create()
-        2 -> GsonBuilder()
+        2 ->
+            GsonBuilder()
                 .registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
                 .registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
                 .registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
@@ -142,21 +143,21 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
                 val numberOfBackups = numberOfBackups()
                 val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""")
                 dir.listFiles { _, filename -> backupRegex.matches(filename) }
-                        .orEmpty()
-                        .sortedByDescending { it.name }
-                        .drop(numberOfBackups - 1)
-                        .forEach { it.delete() }
+                    .orEmpty()
+                    .sortedByDescending { it.name }
+                    .drop(numberOfBackups - 1)
+                    .forEach { it.delete() }
 
                 // Create new file to place backup
                 val newFile = dir.createFile(Backup.getDefaultFilename())
-                        ?: throw Exception("Couldn't create backup file")
+                    ?: throw Exception("Couldn't create backup file")
 
                 newFile.openOutputStream().bufferedWriter().use {
                     parser.toJson(root, it)
                 }
             } else {
                 val file = UniFile.fromUri(context, uri)
-                        ?: throw Exception("Couldn't create backup file")
+                    ?: throw Exception("Couldn't create backup file")
                 file.openOutputStream().bufferedWriter().use {
                     parser.toJson(root, it)
                 }
@@ -268,13 +269,13 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
      */
     fun restoreMangaFetchObservable(source: Source, manga: Manga): Observable<Manga> {
         return source.fetchMangaDetails(manga)
-                .map { networkManga ->
-                    manga.copyFrom(networkManga)
-                    manga.favorite = true
-                    manga.initialized = true
-                    manga.id = insertManga(manga)
-                    manga
-                }
+            .map { networkManga ->
+                manga.copyFrom(networkManga)
+                manga.favorite = true
+                manga.initialized = true
+                manga.id = insertManga(manga)
+                manga
+            }
     }
 
     /**
@@ -286,13 +287,13 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
      */
     fun restoreChapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
         return source.fetchChapterList(manga)
-                .map { syncChaptersWithSource(databaseHelper, it, manga, source) }
-                .doOnNext { pair ->
-                    if (pair.first.isNotEmpty()) {
-                        chapters.forEach { it.manga_id = manga.id }
-                        insertChapters(chapters)
-                    }
+            .map { syncChaptersWithSource(databaseHelper, it, manga, source) }
+            .doOnNext { pair ->
+                if (pair.first.isNotEmpty()) {
+                    chapters.forEach { it.manga_id = manga.id }
+                    insertChapters(chapters)
                 }
+            }
     }
 
     /**
@@ -442,8 +443,9 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
         val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
 
         // Return if fetch is needed
-        if (dbChapters.isEmpty() || dbChapters.size < chapters.size)
+        if (dbChapters.isEmpty() || dbChapters.size < chapters.size) {
             return false
+        }
 
         for (chapter in chapters) {
             val pos = dbChapters.indexOf(chapter)
@@ -468,7 +470,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
      * @return [Manga], null if not found
      */
     internal fun getMangaFromDatabase(manga: Manga): Manga? =
-            databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
+        databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
 
     /**
      * Returns list containing manga from library
@@ -476,7 +478,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
      * @return [Manga] from library
      */
     internal fun getFavoriteManga(): List<Manga> =
-            databaseHelper.getFavoriteMangas().executeAsBlocking()
+        databaseHelper.getFavoriteMangas().executeAsBlocking()
 
     /**
      * Inserts manga and returns id
@@ -484,7 +486,7 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
      * @return id of [Manga], null if not found
      */
     internal fun insertManga(manga: Manga): Long? =
-            databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
+        databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
 
     /**
      * Inserts list of chapters

+ 141 - 132
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt

@@ -60,7 +60,7 @@ class BackupRestoreService : Service() {
          * @return true if the service is running, false otherwise.
          */
         private fun isRunning(context: Context): Boolean =
-                context.isServiceRunning(BackupRestoreService::class.java)
+            context.isServiceRunning(BackupRestoreService::class.java)
 
         /**
          * Starts a service to restore a backup from Json
@@ -143,7 +143,8 @@ class BackupRestoreService : Service() {
         startForeground(Notifications.ID_RESTORE, notifier.showRestoreProgress().build())
 
         wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
-                PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock")
+            PowerManager.PARTIAL_WAKE_LOCK, "BackupRestoreService:WakeLock"
+        )
         wakeLock.acquire()
     }
 
@@ -182,12 +183,13 @@ class BackupRestoreService : Service() {
         subscription?.unsubscribe()
 
         subscription = Observable.using(
-                { db.lowLevel().beginTransaction() },
-                { getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } },
-                { executor.execute { db.lowLevel().endTransaction() } })
-                .doAfterTerminate { stopSelf(startId) }
-                .subscribeOn(Schedulers.from(executor))
-                .subscribe()
+            { db.lowLevel().beginTransaction() },
+            { getRestoreObservable(uri).doOnNext { db.lowLevel().setTransactionSuccessful() } },
+            { executor.execute { db.lowLevel().endTransaction() } }
+        )
+            .doAfterTerminate { stopSelf(startId) }
+            .subscribeOn(Schedulers.from(executor))
+            .subscribe()
 
         return START_NOT_STICKY
     }
@@ -202,79 +204,87 @@ class BackupRestoreService : Service() {
         val startTime = System.currentTimeMillis()
 
         return Observable.just(Unit)
-                .map {
-                    val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader())
-                    val json = JsonParser.parseReader(reader).asJsonObject
+            .map {
+                val reader = JsonReader(contentResolver.openInputStream(uri)!!.bufferedReader())
+                val json = JsonParser.parseReader(reader).asJsonObject
 
-                    // Get parser version
-                    val version = json.get(VERSION)?.asInt ?: 1
+                // Get parser version
+                val version = json.get(VERSION)?.asInt ?: 1
 
-                    // Initialize manager
-                    backupManager = BackupManager(this, version)
+                // Initialize manager
+                backupManager = BackupManager(this, version)
 
-                    val mangasJson = json.get(MANGAS).asJsonArray
+                val mangasJson = json.get(MANGAS).asJsonArray
 
-                    restoreAmount = mangasJson.size() + 1 // +1 for categories
-                    restoreProgress = 0
-                    errors.clear()
+                restoreAmount = mangasJson.size() + 1 // +1 for categories
+                restoreProgress = 0
+                errors.clear()
 
-                    // Restore categories
-                    json.get(CATEGORIES)?.let {
-                        backupManager.restoreCategories(it.asJsonArray)
-                        restoreProgress += 1
-                        showRestoreProgress(restoreProgress, restoreAmount, "Categories added")
-                    }
-
-                    mangasJson
+                // Restore categories
+                json.get(CATEGORIES)?.let {
+                    backupManager.restoreCategories(it.asJsonArray)
+                    restoreProgress += 1
+                    showRestoreProgress(restoreProgress, restoreAmount, "Categories added")
                 }
-                .flatMap { Observable.from(it) }
-                .concatMap {
-                    val obj = it.asJsonObject
-                    val manga = backupManager.parser.fromJson<MangaImpl>(obj.get(MANGA))
-                    val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(obj.get(CHAPTERS)
-                            ?: JsonArray())
-                    val categories = backupManager.parser.fromJson<List<String>>(obj.get(CATEGORIES)
-                            ?: JsonArray())
-                    val history = backupManager.parser.fromJson<List<DHistory>>(obj.get(HISTORY)
-                            ?: JsonArray())
-                    val tracks = backupManager.parser.fromJson<List<TrackImpl>>(obj.get(TRACK)
-                            ?: JsonArray())
-
-                    val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks)
-                    if (observable != null) {
-                        observable
-                    } else {
-                        errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}")
-                        restoreProgress += 1
-                        val content = getString(R.string.dialog_restoring_source_not_found, manga.title.chop(15))
-                        showRestoreProgress(restoreProgress, restoreAmount, manga.title, content)
-                        Observable.just(manga)
-                    }
+
+                mangasJson
+            }
+            .flatMap { Observable.from(it) }
+            .concatMap {
+                val obj = it.asJsonObject
+                val manga = backupManager.parser.fromJson<MangaImpl>(obj.get(MANGA))
+                val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
+                    obj.get(CHAPTERS)
+                        ?: JsonArray()
+                )
+                val categories = backupManager.parser.fromJson<List<String>>(
+                    obj.get(CATEGORIES)
+                        ?: JsonArray()
+                )
+                val history = backupManager.parser.fromJson<List<DHistory>>(
+                    obj.get(HISTORY)
+                        ?: JsonArray()
+                )
+                val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
+                    obj.get(TRACK)
+                        ?: JsonArray()
+                )
+
+                val observable = getMangaRestoreObservable(manga, chapters, categories, history, tracks)
+                if (observable != null) {
+                    observable
+                } else {
+                    errors.add(Date() to "${manga.title} - ${getString(R.string.source_not_found)}")
+                    restoreProgress += 1
+                    val content = getString(R.string.dialog_restoring_source_not_found, manga.title.chop(15))
+                    showRestoreProgress(restoreProgress, restoreAmount, manga.title, content)
+                    Observable.just(manga)
                 }
-                .toList()
-                .doOnNext {
-                    val endTime = System.currentTimeMillis()
-                    val time = endTime - startTime
-                    val logFile = writeErrorLog()
-                    val completeIntent = Intent(BackupConst.INTENT_FILTER).apply {
-                        putExtra(BackupConst.EXTRA_TIME, time)
-                        putExtra(BackupConst.EXTRA_ERRORS, errors.size)
-                        putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent)
-                        putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name)
-                        putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED)
-                    }
-                    sendLocalBroadcast(completeIntent)
+            }
+            .toList()
+            .doOnNext {
+                val endTime = System.currentTimeMillis()
+                val time = endTime - startTime
+                val logFile = writeErrorLog()
+                val completeIntent = Intent(BackupConst.INTENT_FILTER).apply {
+                    putExtra(BackupConst.EXTRA_TIME, time)
+                    putExtra(BackupConst.EXTRA_ERRORS, errors.size)
+                    putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent)
+                    putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name)
+                    putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED)
                 }
-                .doOnError { error ->
-                    Timber.e(error)
-                    writeErrorLog()
-                    val errorIntent = Intent(BackupConst.INTENT_FILTER).apply {
-                        putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR)
-                        putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message)
-                    }
-                    sendLocalBroadcast(errorIntent)
+                sendLocalBroadcast(completeIntent)
+            }
+            .doOnError { error ->
+                Timber.e(error)
+                writeErrorLog()
+                val errorIntent = Intent(BackupConst.INTENT_FILTER).apply {
+                    putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_ERROR)
+                    putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message)
                 }
-                .onErrorReturn { emptyList() }
+                sendLocalBroadcast(errorIntent)
+            }
+            .onErrorReturn { emptyList() }
     }
 
     /**
@@ -347,28 +357,28 @@ class BackupRestoreService : Service() {
         tracks: List<Track>
     ): Observable<Manga> {
         return backupManager.restoreMangaFetchObservable(source, manga)
-                .onErrorReturn {
-                    errors.add(Date() to "${manga.title} - ${it.message}")
-                    manga
-                }
-                .filter { it.id != null }
-                .flatMap {
-                    chapterFetchObservable(source, it, chapters)
-                            // Convert to the manga that contains new chapters.
-                            .map { manga }
-                }
-                .doOnNext {
-                    restoreExtraForManga(it, categories, history, tracks)
-                }
-                .flatMap {
-                    trackingFetchObservable(it, tracks)
-                            // Convert to the manga that contains new chapters.
-                            .map { manga }
-                }
-                .doOnCompleted {
-                    restoreProgress += 1
-                    showRestoreProgress(restoreProgress, restoreAmount, manga.title)
-                }
+            .onErrorReturn {
+                errors.add(Date() to "${manga.title} - ${it.message}")
+                manga
+            }
+            .filter { it.id != null }
+            .flatMap {
+                chapterFetchObservable(source, it, chapters)
+                    // Convert to the manga that contains new chapters.
+                    .map { manga }
+            }
+            .doOnNext {
+                restoreExtraForManga(it, categories, history, tracks)
+            }
+            .flatMap {
+                trackingFetchObservable(it, tracks)
+                    // Convert to the manga that contains new chapters.
+                    .map { manga }
+            }
+            .doOnCompleted {
+                restoreProgress += 1
+                showRestoreProgress(restoreProgress, restoreAmount, manga.title)
+            }
     }
 
     private fun mangaNoFetchObservable(
@@ -379,28 +389,27 @@ class BackupRestoreService : Service() {
         history: List<DHistory>,
         tracks: List<Track>
     ): Observable<Manga> {
-
         return Observable.just(backupManga)
-                .flatMap { manga ->
-                    if (!backupManager.restoreChaptersForManga(manga, chapters)) {
-                        chapterFetchObservable(source, manga, chapters)
-                                .map { manga }
-                    } else {
-                        Observable.just(manga)
-                    }
-                }
-                .doOnNext {
-                    restoreExtraForManga(it, categories, history, tracks)
-                }
-                .flatMap { manga ->
-                    trackingFetchObservable(manga, tracks)
-                            // Convert to the manga that contains new chapters.
-                            .map { manga }
-                }
-                .doOnCompleted {
-                    restoreProgress += 1
-                    showRestoreProgress(restoreProgress, restoreAmount, backupManga.title)
+            .flatMap { manga ->
+                if (!backupManager.restoreChaptersForManga(manga, chapters)) {
+                    chapterFetchObservable(source, manga, chapters)
+                        .map { manga }
+                } else {
+                    Observable.just(manga)
                 }
+            }
+            .doOnNext {
+                restoreExtraForManga(it, categories, history, tracks)
+            }
+            .flatMap { manga ->
+                trackingFetchObservable(manga, tracks)
+                    // Convert to the manga that contains new chapters.
+                    .map { manga }
+            }
+            .doOnCompleted {
+                restoreProgress += 1
+                showRestoreProgress(restoreProgress, restoreAmount, backupManga.title)
+            }
     }
 
     private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) {
@@ -423,11 +432,11 @@ class BackupRestoreService : Service() {
      */
     private fun chapterFetchObservable(source: Source, manga: Manga, chapters: List<Chapter>): Observable<Pair<List<Chapter>, List<Chapter>>> {
         return backupManager.restoreChapterFetchObservable(source, manga, chapters)
-                // If there's any error, return empty update and continue.
-                .onErrorReturn {
-                    errors.add(Date() to "${manga.title} - ${it.message}")
-                    Pair(emptyList(), emptyList())
-                }
+            // If there's any error, return empty update and continue.
+            .onErrorReturn {
+                errors.add(Date() to "${manga.title} - ${it.message}")
+                Pair(emptyList(), emptyList())
+            }
     }
 
     /**
@@ -438,20 +447,20 @@ class BackupRestoreService : Service() {
      */
     private fun trackingFetchObservable(manga: Manga, tracks: List<Track>): Observable<Track> {
         return Observable.from(tracks)
-                .concatMap { track ->
-                    val service = trackManager.getService(track.sync_id)
-                    if (service != null && service.isLogged) {
-                        service.refresh(track)
-                                .doOnNext { db.insertTrack(it).executeAsBlocking() }
-                                .onErrorReturn {
-                                    errors.add(Date() to "${manga.title} - ${it.message}")
-                                    track
-                                }
-                    } else {
-                        errors.add(Date() to "${manga.title} - ${service?.name} not logged in")
-                        Observable.empty()
-                    }
+            .concatMap { track ->
+                val service = trackManager.getService(track.sync_id)
+                if (service != null && service.isLogged) {
+                    service.refresh(track)
+                        .doOnNext { db.insertTrack(it).executeAsBlocking() }
+                        .onErrorReturn {
+                            errors.add(Date() to "${manga.title} - ${it.message}")
+                            track
+                        }
+                } else {
+                    errors.add(Date() to "${manga.title} - ${service?.name} not logged in")
+                    Observable.empty()
                 }
+            }
     }
 
     /**

+ 8 - 5
app/src/main/java/eu/kanade/tachiyomi/data/cache/ChapterCache.kt

@@ -46,10 +46,12 @@ class ChapterCache(private val context: Context) {
     private val gson: Gson by injectLazy()
 
     /** Cache class used for cache management.  */
-    private val diskCache = DiskLruCache.open(File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
-            PARAMETER_APP_VERSION,
-            PARAMETER_VALUE_COUNT,
-            PARAMETER_CACHE_SIZE)
+    private val diskCache = DiskLruCache.open(
+        File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
+        PARAMETER_APP_VERSION,
+        PARAMETER_VALUE_COUNT,
+        PARAMETER_CACHE_SIZE
+    )
 
     /**
      * Returns directory of cache.
@@ -77,8 +79,9 @@ class ChapterCache(private val context: Context) {
      */
     fun removeFileFromCache(file: String): Boolean {
         // Make sure we don't delete the journal file (keeps track of cache).
-        if (file == "journal" || file.startsWith("journal."))
+        if (file == "journal" || file.startsWith("journal.")) {
             return false
+        }
 
         return try {
             // Remove the extension from the file to get the key of the cache

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt

@@ -21,7 +21,7 @@ class CoverCache(private val context: Context) {
      * Cache directory used for cache management.
      */
     private val cacheDir = context.getExternalFilesDir("covers")
-            ?: File(context.filesDir, "covers").also { it.mkdirs() }
+        ?: File(context.filesDir, "covers").also { it.mkdirs() }
 
     /**
      * Returns the cover from cache.
@@ -56,8 +56,9 @@ class CoverCache(private val context: Context) {
      */
     fun deleteFromCache(thumbnailUrl: String?): Boolean {
         // Check if url is empty.
-        if (thumbnailUrl.isNullOrEmpty())
+        if (thumbnailUrl.isNullOrEmpty()) {
             return false
+        }
 
         // Remove file.
         val file = getCoverFile(thumbnailUrl)

+ 11 - 11
app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.kt

@@ -30,19 +30,19 @@ open class DatabaseHelper(context: Context) :
     MangaQueries, ChapterQueries, TrackQueries, CategoryQueries, MangaCategoryQueries, HistoryQueries {
 
     private val configuration = SupportSQLiteOpenHelper.Configuration.builder(context)
-            .name(DbOpenCallback.DATABASE_NAME)
-            .callback(DbOpenCallback())
-            .build()
+        .name(DbOpenCallback.DATABASE_NAME)
+        .callback(DbOpenCallback())
+        .build()
 
     override val db = DefaultStorIOSQLite.builder()
-            .sqliteOpenHelper(RequerySQLiteOpenHelperFactory().create(configuration))
-            .addTypeMapping(Manga::class.java, MangaTypeMapping())
-            .addTypeMapping(Chapter::class.java, ChapterTypeMapping())
-            .addTypeMapping(Track::class.java, TrackTypeMapping())
-            .addTypeMapping(Category::class.java, CategoryTypeMapping())
-            .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
-            .addTypeMapping(History::class.java, HistoryTypeMapping())
-            .build()
+        .sqliteOpenHelper(RequerySQLiteOpenHelperFactory().create(configuration))
+        .addTypeMapping(Manga::class.java, MangaTypeMapping())
+        .addTypeMapping(Chapter::class.java, ChapterTypeMapping())
+        .addTypeMapping(Track::class.java, TrackTypeMapping())
+        .addTypeMapping(Category::class.java, CategoryTypeMapping())
+        .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping())
+        .addTypeMapping(History::class.java, HistoryTypeMapping())
+        .build()
 
     inline fun inTransaction(block: () -> Unit) = db.inTransaction(block)
 

+ 4 - 2
app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt

@@ -44,8 +44,10 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) {
             db.execSQL(ChapterTable.sourceOrderUpdateQuery)
 
             // Fix kissmanga covers after supporting cloudflare
-            db.execSQL("""UPDATE mangas SET thumbnail_url =
-                    REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4""")
+            db.execSQL(
+                """UPDATE mangas SET thumbnail_url =
+                    REPLACE(thumbnail_url, '93.174.95.110', 'kissmanga.com') WHERE source = 4"""
+            )
         }
         if (oldVersion < 3) {
             // Initialize history tables

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/CategoryTypeMapping.kt

@@ -18,22 +18,22 @@ import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER
 import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE
 
 class CategoryTypeMapping : SQLiteTypeMapping<Category>(
-        CategoryPutResolver(),
-        CategoryGetResolver(),
-        CategoryDeleteResolver()
+    CategoryPutResolver(),
+    CategoryGetResolver(),
+    CategoryDeleteResolver()
 )
 
 class CategoryPutResolver : DefaultPutResolver<Category>() {
 
     override fun mapToInsertQuery(obj: Category) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: Category) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: Category) = ContentValues(4).apply {
         put(COL_ID, obj.id)
@@ -56,8 +56,8 @@ class CategoryGetResolver : DefaultGetResolver<Category>() {
 class CategoryDeleteResolver : DefaultDeleteResolver<Category>() {
 
     override fun mapToDeleteQuery(obj: Category) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/ChapterTypeMapping.kt

@@ -26,22 +26,22 @@ import eu.kanade.tachiyomi.data.database.tables.ChapterTable.COL_URL
 import eu.kanade.tachiyomi.data.database.tables.ChapterTable.TABLE
 
 class ChapterTypeMapping : SQLiteTypeMapping<Chapter>(
-        ChapterPutResolver(),
-        ChapterGetResolver(),
-        ChapterDeleteResolver()
+    ChapterPutResolver(),
+    ChapterGetResolver(),
+    ChapterDeleteResolver()
 )
 
 class ChapterPutResolver : DefaultPutResolver<Chapter>() {
 
     override fun mapToInsertQuery(obj: Chapter) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: Chapter) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: Chapter) = ContentValues(11).apply {
         put(COL_ID, obj.id)
@@ -80,8 +80,8 @@ class ChapterGetResolver : DefaultGetResolver<Chapter>() {
 class ChapterDeleteResolver : DefaultDeleteResolver<Chapter>() {
 
     override fun mapToDeleteQuery(obj: Chapter) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/HistoryTypeMapping.kt

@@ -18,22 +18,22 @@ import eu.kanade.tachiyomi.data.database.tables.HistoryTable.COL_TIME_READ
 import eu.kanade.tachiyomi.data.database.tables.HistoryTable.TABLE
 
 class HistoryTypeMapping : SQLiteTypeMapping<History>(
-        HistoryPutResolver(),
-        HistoryGetResolver(),
-        HistoryDeleteResolver()
+    HistoryPutResolver(),
+    HistoryGetResolver(),
+    HistoryDeleteResolver()
 )
 
 open class HistoryPutResolver : DefaultPutResolver<History>() {
 
     override fun mapToInsertQuery(obj: History) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: History) = ContentValues(4).apply {
         put(COL_ID, obj.id)
@@ -56,8 +56,8 @@ class HistoryGetResolver : DefaultGetResolver<History>() {
 class HistoryDeleteResolver : DefaultDeleteResolver<History>() {
 
     override fun mapToDeleteQuery(obj: History) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaCategoryTypeMapping.kt

@@ -16,22 +16,22 @@ import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.COL_MANGA_ID
 import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable.TABLE
 
 class MangaCategoryTypeMapping : SQLiteTypeMapping<MangaCategory>(
-        MangaCategoryPutResolver(),
-        MangaCategoryGetResolver(),
-        MangaCategoryDeleteResolver()
+    MangaCategoryPutResolver(),
+    MangaCategoryGetResolver(),
+    MangaCategoryDeleteResolver()
 )
 
 class MangaCategoryPutResolver : DefaultPutResolver<MangaCategory>() {
 
     override fun mapToInsertQuery(obj: MangaCategory) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: MangaCategory) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: MangaCategory) = ContentValues(3).apply {
         put(COL_ID, obj.id)
@@ -52,8 +52,8 @@ class MangaCategoryGetResolver : DefaultGetResolver<MangaCategory>() {
 class MangaCategoryDeleteResolver : DefaultDeleteResolver<MangaCategory>() {
 
     override fun mapToDeleteQuery(obj: MangaCategory) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt

@@ -29,22 +29,22 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_VIEWER
 import eu.kanade.tachiyomi.data.database.tables.MangaTable.TABLE
 
 class MangaTypeMapping : SQLiteTypeMapping<Manga>(
-        MangaPutResolver(),
-        MangaGetResolver(),
-        MangaDeleteResolver()
+    MangaPutResolver(),
+    MangaGetResolver(),
+    MangaDeleteResolver()
 )
 
 class MangaPutResolver : DefaultPutResolver<Manga>() {
 
     override fun mapToInsertQuery(obj: Manga) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: Manga) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: Manga) = ContentValues(15).apply {
         put(COL_ID, obj.id)
@@ -95,8 +95,8 @@ open class MangaGetResolver : DefaultGetResolver<Manga>(), BaseMangaGetResolver
 class MangaDeleteResolver : DefaultDeleteResolver<Manga>() {
 
     override fun mapToDeleteQuery(obj: Manga) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 13 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt

@@ -27,22 +27,22 @@ import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_TRACKING_URL
 import eu.kanade.tachiyomi.data.database.tables.TrackTable.TABLE
 
 class TrackTypeMapping : SQLiteTypeMapping<Track>(
-        TrackPutResolver(),
-        TrackGetResolver(),
-        TrackDeleteResolver()
+    TrackPutResolver(),
+    TrackGetResolver(),
+    TrackDeleteResolver()
 )
 
 class TrackPutResolver : DefaultPutResolver<Track>() {
 
     override fun mapToInsertQuery(obj: Track) = InsertQuery.builder()
-            .table(TABLE)
-            .build()
+        .table(TABLE)
+        .build()
 
     override fun mapToUpdateQuery(obj: Track) = UpdateQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 
     override fun mapToContentValues(obj: Track) = ContentValues(10).apply {
         put(COL_ID, obj.id)
@@ -83,8 +83,8 @@ class TrackGetResolver : DefaultGetResolver<Track>() {
 class TrackDeleteResolver : DefaultDeleteResolver<Track>() {
 
     override fun mapToDeleteQuery(obj: Track) = DeleteQuery.builder()
-            .table(TABLE)
-            .where("$COL_ID = ?")
-            .whereArgs(obj.id)
-            .build()
+        .table(TABLE)
+        .where("$COL_ID = ?")
+        .whereArgs(obj.id)
+        .build()
 }

+ 16 - 12
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/CategoryQueries.kt

@@ -10,20 +10,24 @@ import eu.kanade.tachiyomi.data.database.tables.CategoryTable
 interface CategoryQueries : DbProvider {
 
     fun getCategories() = db.get()
-            .listOfObjects(Category::class.java)
-            .withQuery(Query.builder()
-                    .table(CategoryTable.TABLE)
-                    .orderBy(CategoryTable.COL_ORDER)
-                    .build())
-            .prepare()
+        .listOfObjects(Category::class.java)
+        .withQuery(
+            Query.builder()
+                .table(CategoryTable.TABLE)
+                .orderBy(CategoryTable.COL_ORDER)
+                .build()
+        )
+        .prepare()
 
     fun getCategoriesForManga(manga: Manga) = db.get()
-            .listOfObjects(Category::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getCategoriesForMangaQuery())
-                    .args(manga.id)
-                    .build())
-            .prepare()
+        .listOfObjects(Category::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getCategoriesForMangaQuery())
+                .args(manga.id)
+                .build()
+        )
+        .prepare()
 
     fun insertCategory(category: Category) = db.put().`object`(category).prepare()
 

+ 58 - 48
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/ChapterQueries.kt

@@ -16,50 +16,60 @@ import java.util.Date
 interface ChapterQueries : DbProvider {
 
     fun getChapters(manga: Manga) = db.get()
-            .listOfObjects(Chapter::class.java)
-            .withQuery(Query.builder()
-                    .table(ChapterTable.TABLE)
-                    .where("${ChapterTable.COL_MANGA_ID} = ?")
-                    .whereArgs(manga.id)
-                    .build())
-            .prepare()
+        .listOfObjects(Chapter::class.java)
+        .withQuery(
+            Query.builder()
+                .table(ChapterTable.TABLE)
+                .where("${ChapterTable.COL_MANGA_ID} = ?")
+                .whereArgs(manga.id)
+                .build()
+        )
+        .prepare()
 
     fun getRecentChapters(date: Date) = db.get()
-            .listOfObjects(MangaChapter::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getRecentsQuery())
-                    .args(date.time)
-                    .observesTables(ChapterTable.TABLE)
-                    .build())
-            .withGetResolver(MangaChapterGetResolver.INSTANCE)
-            .prepare()
+        .listOfObjects(MangaChapter::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getRecentsQuery())
+                .args(date.time)
+                .observesTables(ChapterTable.TABLE)
+                .build()
+        )
+        .withGetResolver(MangaChapterGetResolver.INSTANCE)
+        .prepare()
 
     fun getChapter(id: Long) = db.get()
-            .`object`(Chapter::class.java)
-            .withQuery(Query.builder()
-                    .table(ChapterTable.TABLE)
-                    .where("${ChapterTable.COL_ID} = ?")
-                    .whereArgs(id)
-                    .build())
-            .prepare()
+        .`object`(Chapter::class.java)
+        .withQuery(
+            Query.builder()
+                .table(ChapterTable.TABLE)
+                .where("${ChapterTable.COL_ID} = ?")
+                .whereArgs(id)
+                .build()
+        )
+        .prepare()
 
     fun getChapter(url: String) = db.get()
-            .`object`(Chapter::class.java)
-            .withQuery(Query.builder()
-                    .table(ChapterTable.TABLE)
-                    .where("${ChapterTable.COL_URL} = ?")
-                    .whereArgs(url)
-                    .build())
-            .prepare()
+        .`object`(Chapter::class.java)
+        .withQuery(
+            Query.builder()
+                .table(ChapterTable.TABLE)
+                .where("${ChapterTable.COL_URL} = ?")
+                .whereArgs(url)
+                .build()
+        )
+        .prepare()
 
     fun getChapter(url: String, mangaId: Long) = db.get()
-            .`object`(Chapter::class.java)
-            .withQuery(Query.builder()
-                    .table(ChapterTable.TABLE)
-                    .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
-                    .whereArgs(url, mangaId)
-                    .build())
-            .prepare()
+        .`object`(Chapter::class.java)
+        .withQuery(
+            Query.builder()
+                .table(ChapterTable.TABLE)
+                .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
+                .whereArgs(url, mangaId)
+                .build()
+        )
+        .prepare()
 
     fun insertChapter(chapter: Chapter) = db.put().`object`(chapter).prepare()
 
@@ -70,22 +80,22 @@ interface ChapterQueries : DbProvider {
     fun deleteChapters(chapters: List<Chapter>) = db.delete().objects(chapters).prepare()
 
     fun updateChaptersBackup(chapters: List<Chapter>) = db.put()
-            .objects(chapters)
-            .withPutResolver(ChapterBackupPutResolver())
-            .prepare()
+        .objects(chapters)
+        .withPutResolver(ChapterBackupPutResolver())
+        .prepare()
 
     fun updateChapterProgress(chapter: Chapter) = db.put()
-            .`object`(chapter)
-            .withPutResolver(ChapterProgressPutResolver())
-            .prepare()
+        .`object`(chapter)
+        .withPutResolver(ChapterProgressPutResolver())
+        .prepare()
 
     fun updateChaptersProgress(chapters: List<Chapter>) = db.put()
-            .objects(chapters)
-            .withPutResolver(ChapterProgressPutResolver())
-            .prepare()
+        .objects(chapters)
+        .withPutResolver(ChapterProgressPutResolver())
+        .prepare()
 
     fun fixChaptersSourceOrder(chapters: List<Chapter>) = db.put()
-            .objects(chapters)
-            .withPutResolver(ChapterSourceOrderPutResolver())
-            .prepare()
+        .objects(chapters)
+        .withPutResolver(ChapterSourceOrderPutResolver())
+        .prepare()
 }

+ 48 - 38
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/HistoryQueries.kt

@@ -23,32 +23,38 @@ interface HistoryQueries : DbProvider {
      * @param date recent date range
      */
     fun getRecentManga(date: Date) = db.get()
-            .listOfObjects(MangaChapterHistory::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getRecentMangasQuery())
-                    .args(date.time)
-                    .observesTables(HistoryTable.TABLE)
-                    .build())
-            .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
-            .prepare()
+        .listOfObjects(MangaChapterHistory::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getRecentMangasQuery())
+                .args(date.time)
+                .observesTables(HistoryTable.TABLE)
+                .build()
+        )
+        .withGetResolver(MangaChapterHistoryGetResolver.INSTANCE)
+        .prepare()
 
     fun getHistoryByMangaId(mangaId: Long) = db.get()
-            .listOfObjects(History::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getHistoryByMangaId())
-                    .args(mangaId)
-                    .observesTables(HistoryTable.TABLE)
-                    .build())
-            .prepare()
+        .listOfObjects(History::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getHistoryByMangaId())
+                .args(mangaId)
+                .observesTables(HistoryTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun getHistoryByChapterUrl(chapterUrl: String) = db.get()
-            .`object`(History::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getHistoryByChapterUrl())
-                    .args(chapterUrl)
-                    .observesTables(HistoryTable.TABLE)
-                    .build())
-            .prepare()
+        .`object`(History::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getHistoryByChapterUrl())
+                .args(chapterUrl)
+                .observesTables(HistoryTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     /**
      * Updates the history last read.
@@ -56,9 +62,9 @@ interface HistoryQueries : DbProvider {
      * @param history history object
      */
     fun updateHistoryLastRead(history: History) = db.put()
-            .`object`(history)
-            .withPutResolver(HistoryLastReadPutResolver())
-            .prepare()
+        .`object`(history)
+        .withPutResolver(HistoryLastReadPutResolver())
+        .prepare()
 
     /**
      * Updates the history last read.
@@ -66,21 +72,25 @@ interface HistoryQueries : DbProvider {
      * @param historyList history object list
      */
     fun updateHistoryLastRead(historyList: List<History>) = db.put()
-            .objects(historyList)
-            .withPutResolver(HistoryLastReadPutResolver())
-            .prepare()
+        .objects(historyList)
+        .withPutResolver(HistoryLastReadPutResolver())
+        .prepare()
 
     fun deleteHistory() = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(HistoryTable.TABLE)
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(HistoryTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun deleteHistoryNoLastRead() = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(HistoryTable.TABLE)
-                    .where("${HistoryTable.COL_LAST_READ} = ?")
-                    .whereArgs(0)
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(HistoryTable.TABLE)
+                .where("${HistoryTable.COL_LAST_READ} = ?")
+                .whereArgs(0)
+                .build()
+        )
+        .prepare()
 }

+ 8 - 6
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaCategoryQueries.kt

@@ -15,12 +15,14 @@ interface MangaCategoryQueries : DbProvider {
     fun insertMangasCategories(mangasCategories: List<MangaCategory>) = db.put().objects(mangasCategories).prepare()
 
     fun deleteOldMangasCategories(mangas: List<Manga>) = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(MangaCategoryTable.TABLE)
-                    .where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
-                    .whereArgs(*mangas.map { it.id }.toTypedArray())
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(MangaCategoryTable.TABLE)
+                .where("${MangaCategoryTable.COL_MANGA_ID} IN (${Queries.placeholders(mangas.size)})")
+                .whereArgs(*mangas.map { it.id }.toTypedArray())
+                .build()
+        )
+        .prepare()
 
     fun setMangaCategories(mangasCategories: List<MangaCategory>, mangas: List<Manga>) {
         db.inTransaction {

+ 97 - 77
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt

@@ -20,117 +20,137 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable
 interface MangaQueries : DbProvider {
 
     fun getMangas() = db.get()
-            .listOfObjects(Manga::class.java)
-            .withQuery(Query.builder()
-                    .table(MangaTable.TABLE)
-                    .build())
-            .prepare()
+        .listOfObjects(Manga::class.java)
+        .withQuery(
+            Query.builder()
+                .table(MangaTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun getLibraryMangas() = db.get()
-            .listOfObjects(LibraryManga::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(libraryQuery)
-                    .observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
-                    .build())
-            .withGetResolver(LibraryMangaGetResolver.INSTANCE)
-            .prepare()
+        .listOfObjects(LibraryManga::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(libraryQuery)
+                .observesTables(MangaTable.TABLE, ChapterTable.TABLE, MangaCategoryTable.TABLE, CategoryTable.TABLE)
+                .build()
+        )
+        .withGetResolver(LibraryMangaGetResolver.INSTANCE)
+        .prepare()
 
     fun getFavoriteMangas() = db.get()
-            .listOfObjects(Manga::class.java)
-            .withQuery(Query.builder()
-                    .table(MangaTable.TABLE)
-                    .where("${MangaTable.COL_FAVORITE} = ?")
-                    .whereArgs(1)
-                    .orderBy(MangaTable.COL_TITLE)
-                    .build())
-            .prepare()
+        .listOfObjects(Manga::class.java)
+        .withQuery(
+            Query.builder()
+                .table(MangaTable.TABLE)
+                .where("${MangaTable.COL_FAVORITE} = ?")
+                .whereArgs(1)
+                .orderBy(MangaTable.COL_TITLE)
+                .build()
+        )
+        .prepare()
 
     fun getManga(url: String, sourceId: Long) = db.get()
-            .`object`(Manga::class.java)
-            .withQuery(Query.builder()
-                    .table(MangaTable.TABLE)
-                    .where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
-                    .whereArgs(url, sourceId)
-                    .build())
-            .prepare()
+        .`object`(Manga::class.java)
+        .withQuery(
+            Query.builder()
+                .table(MangaTable.TABLE)
+                .where("${MangaTable.COL_URL} = ? AND ${MangaTable.COL_SOURCE} = ?")
+                .whereArgs(url, sourceId)
+                .build()
+        )
+        .prepare()
 
     fun getManga(id: Long) = db.get()
-            .`object`(Manga::class.java)
-            .withQuery(Query.builder()
-                    .table(MangaTable.TABLE)
-                    .where("${MangaTable.COL_ID} = ?")
-                    .whereArgs(id)
-                    .build())
-            .prepare()
+        .`object`(Manga::class.java)
+        .withQuery(
+            Query.builder()
+                .table(MangaTable.TABLE)
+                .where("${MangaTable.COL_ID} = ?")
+                .whereArgs(id)
+                .build()
+        )
+        .prepare()
 
     fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
 
     fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
 
     fun updateFlags(manga: Manga) = db.put()
-            .`object`(manga)
-            .withPutResolver(MangaFlagsPutResolver())
-            .prepare()
+        .`object`(manga)
+        .withPutResolver(MangaFlagsPutResolver())
+        .prepare()
 
     fun updateLastUpdated(manga: Manga) = db.put()
-            .`object`(manga)
-            .withPutResolver(MangaLastUpdatedPutResolver())
-            .prepare()
+        .`object`(manga)
+        .withPutResolver(MangaLastUpdatedPutResolver())
+        .prepare()
 
     fun updateMangaFavorite(manga: Manga) = db.put()
-            .`object`(manga)
-            .withPutResolver(MangaFavoritePutResolver())
-            .prepare()
+        .`object`(manga)
+        .withPutResolver(MangaFavoritePutResolver())
+        .prepare()
 
     fun updateMangaViewer(manga: Manga) = db.put()
-            .`object`(manga)
-            .withPutResolver(MangaViewerPutResolver())
-            .prepare()
+        .`object`(manga)
+        .withPutResolver(MangaViewerPutResolver())
+        .prepare()
 
     fun updateMangaTitle(manga: Manga) = db.put()
-            .`object`(manga)
-            .withPutResolver(MangaTitlePutResolver())
-            .prepare()
+        .`object`(manga)
+        .withPutResolver(MangaTitlePutResolver())
+        .prepare()
 
     fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
 
     fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
 
     fun deleteMangasNotInLibrary() = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(MangaTable.TABLE)
-                    .where("${MangaTable.COL_FAVORITE} = ?")
-                    .whereArgs(0)
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(MangaTable.TABLE)
+                .where("${MangaTable.COL_FAVORITE} = ?")
+                .whereArgs(0)
+                .build()
+        )
+        .prepare()
 
     fun deleteMangas() = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(MangaTable.TABLE)
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(MangaTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun getLastReadManga() = db.get()
-            .listOfObjects(Manga::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getLastReadMangaQuery())
-                    .observesTables(MangaTable.TABLE)
-                    .build())
-            .prepare()
+        .listOfObjects(Manga::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getLastReadMangaQuery())
+                .observesTables(MangaTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun getTotalChapterManga() = db.get()
-            .listOfObjects(Manga::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getTotalChapterMangaQuery())
-                    .observesTables(MangaTable.TABLE)
-                    .build())
-            .prepare()
+        .listOfObjects(Manga::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getTotalChapterMangaQuery())
+                .observesTables(MangaTable.TABLE)
+                .build()
+        )
+        .prepare()
 
     fun getLatestChapterManga() = db.get()
-            .listOfObjects(Manga::class.java)
-            .withQuery(RawQuery.builder()
-                    .query(getLatestChapterMangaQuery())
-                    .observesTables(MangaTable.TABLE)
-                    .build())
-            .prepare()
+        .listOfObjects(Manga::class.java)
+        .withQuery(
+            RawQuery.builder()
+                .query(getLatestChapterMangaQuery())
+                .observesTables(MangaTable.TABLE)
+                .build()
+        )
+        .prepare()
 }

+ 18 - 9
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/RawQueries.kt

@@ -9,7 +9,8 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga
 /**
  * Query to get the manga from the library, with their categories and unread count.
  */
-val libraryQuery = """
+val libraryQuery =
+    """
     SELECT M.*, COALESCE(MC.${MangaCategory.COL_CATEGORY_ID}, 0) AS ${Manga.COL_CATEGORY}
     FROM (
         SELECT ${Manga.TABLE}.*, COALESCE(C.unread, 0) AS ${Manga.COL_UNREAD}
@@ -33,7 +34,8 @@ val libraryQuery = """
 /**
  * Query to get the recent chapters of manga from the library up to a date.
  */
-fun getRecentsQuery() = """
+fun getRecentsQuery() =
+    """
     SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, * FROM ${Manga.TABLE} JOIN ${Chapter.TABLE}
     ON ${Manga.TABLE}.${Manga.COL_ID} = ${Chapter.TABLE}.${Chapter.COL_MANGA_ID}
     WHERE ${Manga.COL_FAVORITE} = 1 AND ${Chapter.COL_DATE_UPLOAD} > ?
@@ -47,7 +49,8 @@ fun getRecentsQuery() = """
  * and are read after the given time period
  * @return return limit is 25
  */
-fun getRecentMangasQuery() = """
+fun getRecentMangasQuery() =
+    """
     SELECT ${Manga.TABLE}.${Manga.COL_URL} as mangaUrl, ${Manga.TABLE}.*, ${Chapter.TABLE}.*, ${History.TABLE}.*
     FROM ${Manga.TABLE}
     JOIN ${Chapter.TABLE}
@@ -65,7 +68,8 @@ fun getRecentMangasQuery() = """
     LIMIT 25
 """
 
-fun getHistoryByMangaId() = """
+fun getHistoryByMangaId() =
+    """
     SELECT ${History.TABLE}.*
     FROM ${History.TABLE}
     JOIN ${Chapter.TABLE}
@@ -73,7 +77,8 @@ fun getHistoryByMangaId() = """
     WHERE ${Chapter.TABLE}.${Chapter.COL_MANGA_ID} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
 """
 
-fun getHistoryByChapterUrl() = """
+fun getHistoryByChapterUrl() =
+    """
     SELECT ${History.TABLE}.*
     FROM ${History.TABLE}
     JOIN ${Chapter.TABLE}
@@ -81,7 +86,8 @@ fun getHistoryByChapterUrl() = """
     WHERE ${Chapter.TABLE}.${Chapter.COL_URL} = ? AND ${History.TABLE}.${History.COL_CHAPTER_ID} = ${Chapter.TABLE}.${Chapter.COL_ID}
 """
 
-fun getLastReadMangaQuery() = """
+fun getLastReadMangaQuery() =
+    """
     SELECT ${Manga.TABLE}.*, MAX(${History.TABLE}.${History.COL_LAST_READ}) AS max
     FROM ${Manga.TABLE}
     JOIN ${Chapter.TABLE}
@@ -93,7 +99,8 @@ fun getLastReadMangaQuery() = """
     ORDER BY max DESC
 """
 
-fun getTotalChapterMangaQuery() = """
+fun getTotalChapterMangaQuery() =
+    """
     SELECT ${Manga.TABLE}.*
     FROM ${Manga.TABLE}
     JOIN ${Chapter.TABLE}
@@ -102,7 +109,8 @@ fun getTotalChapterMangaQuery() = """
     ORDER by COUNT(*)
 """
 
-fun getLatestChapterMangaQuery() = """
+fun getLatestChapterMangaQuery() =
+    """
     SELECT ${Manga.TABLE}.*, MAX(${Chapter.TABLE}.${Chapter.COL_DATE_UPLOAD}) AS max
     FROM ${Manga.TABLE}
     JOIN ${Chapter.TABLE}
@@ -114,7 +122,8 @@ fun getLatestChapterMangaQuery() = """
 /**
  * Query to get the categories for a manga.
  */
-fun getCategoriesForMangaQuery() = """
+fun getCategoriesForMangaQuery() =
+    """
     SELECT ${Category.TABLE}.* FROM ${Category.TABLE}
     JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} =
     ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}

+ 17 - 13
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/TrackQueries.kt

@@ -11,23 +11,27 @@ import eu.kanade.tachiyomi.data.track.TrackService
 interface TrackQueries : DbProvider {
 
     fun getTracks(manga: Manga) = db.get()
-            .listOfObjects(Track::class.java)
-            .withQuery(Query.builder()
-                    .table(TrackTable.TABLE)
-                    .where("${TrackTable.COL_MANGA_ID} = ?")
-                    .whereArgs(manga.id)
-                    .build())
-            .prepare()
+        .listOfObjects(Track::class.java)
+        .withQuery(
+            Query.builder()
+                .table(TrackTable.TABLE)
+                .where("${TrackTable.COL_MANGA_ID} = ?")
+                .whereArgs(manga.id)
+                .build()
+        )
+        .prepare()
 
     fun insertTrack(track: Track) = db.put().`object`(track).prepare()
 
     fun insertTracks(tracks: List<Track>) = db.put().objects(tracks).prepare()
 
     fun deleteTrackForManga(manga: Manga, sync: TrackService) = db.delete()
-            .byQuery(DeleteQuery.builder()
-                    .table(TrackTable.TABLE)
-                    .where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
-                    .whereArgs(manga.id, sync.id)
-                    .build())
-            .prepare()
+        .byQuery(
+            DeleteQuery.builder()
+                .table(TrackTable.TABLE)
+                .where("${TrackTable.COL_MANGA_ID} = ? AND ${TrackTable.COL_SYNC_ID} = ?")
+                .whereArgs(manga.id, sync.id)
+                .build()
+        )
+        .prepare()
 }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterBackupPutResolver.kt

@@ -20,10 +20,10 @@ class ChapterBackupPutResolver : PutResolver<Chapter>() {
     }
 
     fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder()
-            .table(ChapterTable.TABLE)
-            .where("${ChapterTable.COL_URL} = ?")
-            .whereArgs(chapter.url)
-            .build()
+        .table(ChapterTable.TABLE)
+        .where("${ChapterTable.COL_URL} = ?")
+        .whereArgs(chapter.url)
+        .build()
 
     fun mapToContentValues(chapter: Chapter) = ContentValues(3).apply {
         put(ChapterTable.COL_READ, chapter.read)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterProgressPutResolver.kt

@@ -20,10 +20,10 @@ class ChapterProgressPutResolver : PutResolver<Chapter>() {
     }
 
     fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder()
-            .table(ChapterTable.TABLE)
-            .where("${ChapterTable.COL_ID} = ?")
-            .whereArgs(chapter.id)
-            .build()
+        .table(ChapterTable.TABLE)
+        .where("${ChapterTable.COL_ID} = ?")
+        .whereArgs(chapter.id)
+        .build()
 
     fun mapToContentValues(chapter: Chapter) = ContentValues(3).apply {
         put(ChapterTable.COL_READ, chapter.read)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/ChapterSourceOrderPutResolver.kt

@@ -20,10 +20,10 @@ class ChapterSourceOrderPutResolver : PutResolver<Chapter>() {
     }
 
     fun mapToUpdateQuery(chapter: Chapter) = UpdateQuery.builder()
-            .table(ChapterTable.TABLE)
-            .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
-            .whereArgs(chapter.url, chapter.manga_id)
-            .build()
+        .table(ChapterTable.TABLE)
+        .where("${ChapterTable.COL_URL} = ? AND ${ChapterTable.COL_MANGA_ID} = ?")
+        .whereArgs(chapter.url, chapter.manga_id)
+        .build()
 
     fun mapToContentValues(chapter: Chapter) = ContentValues(1).apply {
         put(ChapterTable.COL_SOURCE_ORDER, chapter.source_order)

+ 8 - 6
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/HistoryLastReadPutResolver.kt

@@ -19,11 +19,13 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
     override fun performPut(@NonNull db: StorIOSQLite, @NonNull history: History): PutResult = db.inTransactionReturn {
         val updateQuery = mapToUpdateQuery(history)
 
-        val cursor = db.lowLevel().query(Query.builder()
+        val cursor = db.lowLevel().query(
+            Query.builder()
                 .table(updateQuery.table())
                 .where(updateQuery.where())
                 .whereArgs(updateQuery.whereArgs())
-                .build())
+                .build()
+        )
 
         val putResult: PutResult
 
@@ -46,10 +48,10 @@ class HistoryLastReadPutResolver : HistoryPutResolver() {
      * @param obj history object
      */
     override fun mapToUpdateQuery(obj: History) = UpdateQuery.builder()
-            .table(HistoryTable.TABLE)
-            .where("${HistoryTable.COL_CHAPTER_ID} = ?")
-            .whereArgs(obj.chapter_id)
-            .build()
+        .table(HistoryTable.TABLE)
+        .where("${HistoryTable.COL_CHAPTER_ID} = ?")
+        .whereArgs(obj.chapter_id)
+        .build()
 
     /**
      * Create content query

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFavoritePutResolver.kt

@@ -20,10 +20,10 @@ class MangaFavoritePutResolver : PutResolver<Manga>() {
     }
 
     fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-            .table(MangaTable.TABLE)
-            .where("${MangaTable.COL_ID} = ?")
-            .whereArgs(manga.id)
-            .build()
+        .table(MangaTable.TABLE)
+        .where("${MangaTable.COL_ID} = ?")
+        .whereArgs(manga.id)
+        .build()
 
     fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
         put(MangaTable.COL_FAVORITE, manga.favorite)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt

@@ -20,10 +20,10 @@ class MangaFlagsPutResolver : PutResolver<Manga>() {
     }
 
     fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-            .table(MangaTable.TABLE)
-            .where("${MangaTable.COL_ID} = ?")
-            .whereArgs(manga.id)
-            .build()
+        .table(MangaTable.TABLE)
+        .where("${MangaTable.COL_ID} = ?")
+        .whereArgs(manga.id)
+        .build()
 
     fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
         put(MangaTable.COL_CHAPTER_FLAGS, manga.chapter_flags)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaLastUpdatedPutResolver.kt

@@ -20,10 +20,10 @@ class MangaLastUpdatedPutResolver : PutResolver<Manga>() {
     }
 
     fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-            .table(MangaTable.TABLE)
-            .where("${MangaTable.COL_ID} = ?")
-            .whereArgs(manga.id)
-            .build()
+        .table(MangaTable.TABLE)
+        .where("${MangaTable.COL_ID} = ?")
+        .whereArgs(manga.id)
+        .build()
 
     fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
         put(MangaTable.COL_LAST_UPDATE, manga.last_update)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaTitlePutResolver.kt

@@ -20,10 +20,10 @@ class MangaTitlePutResolver : PutResolver<Manga>() {
     }
 
     fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-            .table(MangaTable.TABLE)
-            .where("${MangaTable.COL_ID} = ?")
-            .whereArgs(manga.id)
-            .build()
+        .table(MangaTable.TABLE)
+        .where("${MangaTable.COL_ID} = ?")
+        .whereArgs(manga.id)
+        .build()
 
     fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
         put(MangaTable.COL_TITLE, manga.title)

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt

@@ -20,10 +20,10 @@ class MangaViewerPutResolver : PutResolver<Manga>() {
     }
 
     fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-            .table(MangaTable.TABLE)
-            .where("${MangaTable.COL_ID} = ?")
-            .whereArgs(manga.id)
-            .build()
+        .table(MangaTable.TABLE)
+        .where("${MangaTable.COL_ID} = ?")
+        .whereArgs(manga.id)
+        .build()
 
     fun mapToContentValues(manga: Manga) = ContentValues(1).apply {
         put(MangaTable.COL_VIEWER, manga.viewer)

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/CategoryTable.kt

@@ -13,7 +13,8 @@ object CategoryTable {
     const val COL_FLAGS = "flags"
 
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_NAME TEXT NOT NULL,
             $COL_ORDER INTEGER NOT NULL,

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/ChapterTable.kt

@@ -29,7 +29,8 @@ object ChapterTable {
     const val COL_SOURCE_ORDER = "source_order"
 
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_MANGA_ID INTEGER NOT NULL,
             $COL_URL TEXT NOT NULL,
@@ -51,7 +52,7 @@ object ChapterTable {
 
     val createUnreadChaptersIndexQuery: String
         get() = "CREATE INDEX ${TABLE}_unread_by_manga_index ON $TABLE($COL_MANGA_ID, $COL_READ) " +
-                "WHERE $COL_READ = 0"
+            "WHERE $COL_READ = 0"
 
     val sourceOrderUpdateQuery: String
         get() = "ALTER TABLE $TABLE ADD COLUMN $COL_SOURCE_ORDER INTEGER DEFAULT 0"

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/HistoryTable.kt

@@ -31,7 +31,8 @@ object HistoryTable {
      * query to create history table
      */
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_CHAPTER_ID INTEGER NOT NULL UNIQUE,
             $COL_LAST_READ LONG,

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaCategoryTable.kt

@@ -11,7 +11,8 @@ object MangaCategoryTable {
     const val COL_CATEGORY_ID = "category_id"
 
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_MANGA_ID INTEGER NOT NULL,
             $COL_CATEGORY_ID INTEGER NOT NULL,

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt

@@ -39,7 +39,8 @@ object MangaTable {
     const val COL_CATEGORY = "category"
 
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_SOURCE INTEGER NOT NULL,
             $COL_URL TEXT NOT NULL,
@@ -62,5 +63,5 @@ object MangaTable {
 
     val createLibraryIndexQuery: String
         get() = "CREATE INDEX library_${COL_FAVORITE}_index ON $TABLE($COL_FAVORITE) " +
-                "WHERE $COL_FAVORITE = 1"
+            "WHERE $COL_FAVORITE = 1"
 }

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt

@@ -31,7 +31,8 @@ object TrackTable {
     const val COL_FINISH_DATE = "finish_date"
 
     val createTableQuery: String
-        get() = """CREATE TABLE $TABLE(
+        get() =
+            """CREATE TABLE $TABLE(
             $COL_ID INTEGER NOT NULL PRIMARY KEY,
             $COL_MANGA_ID INTEGER NOT NULL,
             $COL_SYNC_ID INTEGER NOT NULL,

+ 12 - 12
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadCache.kt

@@ -100,8 +100,8 @@ class DownloadCache(
             val mangaDir = sourceDir.files[provider.getMangaDirName(manga)]
             if (mangaDir != null) {
                 return mangaDir.files
-                        .filter { !it.endsWith(Downloader.TMP_DIR_SUFFIX) }
-                        .size
+                    .filter { !it.endsWith(Downloader.TMP_DIR_SUFFIX) }
+                    .size
             }
         }
         return 0
@@ -125,26 +125,26 @@ class DownloadCache(
         val onlineSources = sourceManager.getOnlineSources()
 
         val sourceDirs = rootDir.dir.listFiles()
-                .orEmpty()
-                .associate { it.name to SourceDirectory(it) }
-                .mapNotNullKeys { entry ->
-                    onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id
-                }
+            .orEmpty()
+            .associate { it.name to SourceDirectory(it) }
+            .mapNotNullKeys { entry ->
+                onlineSources.find { provider.getSourceDirName(it) == entry.key }?.id
+            }
 
         rootDir.files = sourceDirs
 
         sourceDirs.values.forEach { sourceDir ->
             val mangaDirs = sourceDir.dir.listFiles()
-                    .orEmpty()
-                    .associateNotNullKeys { it.name to MangaDirectory(it) }
+                .orEmpty()
+                .associateNotNullKeys { it.name to MangaDirectory(it) }
 
             sourceDir.files = mangaDirs
 
             mangaDirs.values.forEach { mangaDir ->
                 val chapterDirs = mangaDir.dir.listFiles()
-                        .orEmpty()
-                        .mapNotNull { it.name }
-                        .toHashSet()
+                    .orEmpty()
+                    .mapNotNull { it.name }
+                    .toHashSet()
 
                 mangaDir.files = chapterDirs
             }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt

@@ -148,16 +148,16 @@ class DownloadManager(private val context: Context) {
     private fun buildPageList(chapterDir: UniFile?): Observable<List<Page>> {
         return Observable.fromCallable {
             val files = chapterDir?.listFiles().orEmpty()
-                    .filter { "image" in it.type.orEmpty() }
+                .filter { "image" in it.type.orEmpty() }
 
             if (files.isEmpty()) {
                 throw Exception("Page list is empty")
             }
 
             files.sortedBy { it.name }
-                    .mapIndexed { i, file ->
-                        Page(i, uri = file.uri).apply { status = Page.READY }
-                    }
+                .mapIndexed { i, file ->
+                    Page(i, uri = file.uri).apply { status = Page.READY }
+                }
         }
     }
 

+ 20 - 12
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt

@@ -87,13 +87,15 @@ internal class DownloadNotifier(private val context: Context) {
                 setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
                 isDownloading = true
                 // Pause action
-                addAction(R.drawable.ic_pause_24dp,
-                        context.getString(R.string.action_pause),
-                        NotificationReceiver.pauseDownloadsPendingBroadcast(context))
+                addAction(
+                    R.drawable.ic_pause_24dp,
+                    context.getString(R.string.action_pause),
+                    NotificationReceiver.pauseDownloadsPendingBroadcast(context)
+                )
             }
 
             val downloadingProgressText = context.getString(R.string.chapter_downloading_progress)
-                    .format(download.downloadedImages, download.pages!!.size)
+                .format(download.downloadedImages, download.pages!!.size)
 
             if (preferences.hideNotificationContent()) {
                 setContentTitle(downloadingProgressText)
@@ -126,13 +128,17 @@ internal class DownloadNotifier(private val context: Context) {
             // Open download manager when clicked
             setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
             // Resume action
-            addAction(R.drawable.ic_play_arrow_24dp,
-                    context.getString(R.string.action_resume),
-                    NotificationReceiver.resumeDownloadsPendingBroadcast(context))
+            addAction(
+                R.drawable.ic_play_arrow_24dp,
+                context.getString(R.string.action_resume),
+                NotificationReceiver.resumeDownloadsPendingBroadcast(context)
+            )
             // Clear action
-            addAction(R.drawable.ic_close_24dp,
-                    context.getString(R.string.action_cancel_all),
-                    NotificationReceiver.clearDownloadsPendingBroadcast(context))
+            addAction(
+                R.drawable.ic_close_24dp,
+                context.getString(R.string.action_cancel_all),
+                NotificationReceiver.clearDownloadsPendingBroadcast(context)
+            )
         }
 
         // Show notification.
@@ -173,8 +179,10 @@ internal class DownloadNotifier(private val context: Context) {
     fun onError(error: String? = null, chapter: String? = null) {
         // Create notification
         with(notificationBuilder) {
-            setContentTitle(chapter
-                    ?: context.getString(R.string.download_notifier_downloader_title))
+            setContentTitle(
+                chapter
+                    ?: context.getString(R.string.download_notifier_downloader_title)
+            )
             setContentText(error ?: context.getString(R.string.download_notifier_unknown_error))
             setSmallIcon(android.R.drawable.stat_sys_warning)
             clearActions()

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt

@@ -52,8 +52,8 @@ class DownloadProvider(private val context: Context) {
     internal fun getMangaDir(manga: Manga, source: Source): UniFile {
         try {
             return downloadsDir
-                    .createDirectory(getSourceDirName(source))
-                    .createDirectory(getMangaDirName(manga))
+                .createDirectory(getSourceDirName(source))
+                .createDirectory(getMangaDirName(manga))
         } catch (e: NullPointerException) {
             throw Exception(context.getString(R.string.invalid_download_dir))
         }

+ 11 - 7
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt

@@ -123,14 +123,17 @@ class DownloadService : Service() {
      */
     private fun listenNetworkChanges() {
         subscriptions += ReactiveNetwork.observeNetworkConnectivity(applicationContext)
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe({ state ->
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(
+                { state ->
                     onNetworkStateChanged(state)
-                }, {
+                },
+                {
                     toast(R.string.download_queue_error)
                     stopSelf()
-                })
+                }
+            )
     }
 
     /**
@@ -162,10 +165,11 @@ class DownloadService : Service() {
      */
     private fun listenDownloaderState() {
         subscriptions += downloadManager.runningRelay.subscribe { running ->
-            if (running)
+            if (running) {
                 wakeLock.acquireIfNeeded()
-            else
+            } else {
                 wakeLock.releaseIfNeeded()
+            }
         }
     }
 

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadStore.kt

@@ -77,9 +77,9 @@ class DownloadStore(
      */
     fun restore(): List<Download> {
         val objs = preferences.all
-                .mapNotNull { it.value as? String }
-                .mapNotNull { deserialize(it) }
-                .sortedBy { it.order }
+            .mapNotNull { it.value as? String }
+            .mapNotNull { deserialize(it) }
+            .sortedBy { it.order }
 
         val downloads = mutableListOf<Download>()
         if (objs.isNotEmpty()) {

+ 96 - 90
app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt

@@ -100,11 +100,13 @@ class Downloader(
      * @return true if the downloader is started, false otherwise.
      */
     fun start(): Boolean {
-        if (isRunning || queue.isEmpty())
+        if (isRunning || queue.isEmpty()) {
             return false
+        }
 
-        if (!subscriptions.hasSubscriptions())
+        if (!subscriptions.hasSubscriptions()) {
             initializeSubscriptions()
+        }
 
         val pending = queue.filter { it.status != Download.DOWNLOADED }
         pending.forEach { if (it.status != Download.QUEUE) it.status = Download.QUEUE }
@@ -119,8 +121,8 @@ class Downloader(
     fun stop(reason: String? = null) {
         destroySubscriptions()
         queue
-                .filter { it.status == Download.DOWNLOADING }
-                .forEach { it.status = Download.ERROR }
+            .filter { it.status == Download.DOWNLOADING }
+            .forEach { it.status = Download.ERROR }
 
         if (reason != null) {
             notifier.onWarning(reason)
@@ -140,8 +142,8 @@ class Downloader(
     fun pause() {
         destroySubscriptions()
         queue
-                .filter { it.status == Download.DOWNLOADING }
-                .forEach { it.status = Download.QUEUE }
+            .filter { it.status == Download.DOWNLOADING }
+            .forEach { it.status = Download.QUEUE }
         notifier.paused = true
     }
 
@@ -156,8 +158,8 @@ class Downloader(
         // Needed to update the chapter view
         if (isNotification) {
             queue
-                    .filter { it.status == Download.QUEUE }
-                    .forEach { it.status = Download.NOT_DOWNLOADED }
+                .filter { it.status == Download.QUEUE }
+                .forEach { it.status = Download.NOT_DOWNLOADED }
         }
         queue.clear()
         notifier.dismiss()
@@ -174,16 +176,19 @@ class Downloader(
         subscriptions.clear()
 
         subscriptions += downloadsRelay.concatMapIterable { it }
-                .concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) }
-                .onBackpressureBuffer()
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe({
+            .concatMap { downloadChapter(it).subscribeOn(Schedulers.io()) }
+            .onBackpressureBuffer()
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(
+                {
                     completeDownload(it)
-                }, { error ->
+                },
+                { error ->
                     DownloadService.stop(context)
                     Timber.e(error)
                     notifier.onError(error.message)
-                })
+                }
+            )
     }
 
     /**
@@ -212,20 +217,20 @@ class Downloader(
             val mangaDir = provider.findMangaDir(manga, source)
 
             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 }
+                // 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 }
         }
 
         // 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) }
+            // 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) }
 
         if (chaptersToQueue.isNotEmpty()) {
             queue.addAll(chaptersToQueue)
@@ -255,43 +260,43 @@ class Downloader(
         val pageListObservable = if (download.pages == null) {
             // Pull page list from network and add them to download object
             download.source.fetchPageList(download.chapter)
-                    .doOnNext { pages ->
-                        if (pages.isEmpty()) {
-                            throw Exception("Page list is empty")
-                        }
-                        download.pages = pages
+                .doOnNext { pages ->
+                    if (pages.isEmpty()) {
+                        throw Exception("Page list is empty")
                     }
+                    download.pages = pages
+                }
         } else {
             // Or if the page list already exists, start from the file
             Observable.just(download.pages!!)
         }
 
         pageListObservable
-                .doOnNext { _ ->
-                    // Delete all temporary (unfinished) files
-                    tmpDir.listFiles()
-                            ?.filter { it.name!!.endsWith(".tmp") }
-                            ?.forEach { it.delete() }
-
-                    download.downloadedImages = 0
-                    download.status = Download.DOWNLOADING
-                }
-                // Get all the URLs to the source images, fetch pages if necessary
-                .flatMap { download.source.fetchAllImageUrlsFromPageList(it) }
-                // Start downloading images, consider we can have downloaded images already
-                .concatMap { page -> getOrDownloadImage(page, download, tmpDir) }
-                // Do when page is downloaded.
-                .doOnNext { notifier.onProgressChange(download) }
-                .toList()
-                .map { download }
-                // Do after download completes
-                .doOnNext { ensureSuccessfulDownload(download, mangaDir, tmpDir, chapterDirname) }
-                // If the page list threw, it will resume here
-                .onErrorReturn { error ->
-                    download.status = Download.ERROR
-                    notifier.onError(error.message, download.chapter.name)
-                    download
-                }
+            .doOnNext { _ ->
+                // Delete all temporary (unfinished) files
+                tmpDir.listFiles()
+                    ?.filter { it.name!!.endsWith(".tmp") }
+                    ?.forEach { it.delete() }
+
+                download.downloadedImages = 0
+                download.status = Download.DOWNLOADING
+            }
+            // Get all the URLs to the source images, fetch pages if necessary
+            .flatMap { download.source.fetchAllImageUrlsFromPageList(it) }
+            // Start downloading images, consider we can have downloaded images already
+            .concatMap { page -> getOrDownloadImage(page, download, tmpDir) }
+            // Do when page is downloaded.
+            .doOnNext { notifier.onProgressChange(download) }
+            .toList()
+            .map { download }
+            // Do after download completes
+            .doOnNext { ensureSuccessfulDownload(download, mangaDir, tmpDir, chapterDirname) }
+            // If the page list threw, it will resume here
+            .onErrorReturn { error ->
+                download.status = Download.ERROR
+                notifier.onError(error.message, download.chapter.name)
+                download
+            }
     }
 
     /**
@@ -304,8 +309,9 @@ class Downloader(
      */
     private fun getOrDownloadImage(page: Page, download: Download, tmpDir: UniFile): Observable<Page> {
         // If the image URL is empty, do nothing
-        if (page.imageUrl == null)
+        if (page.imageUrl == null) {
             return Observable.just(page)
+        }
 
         val filename = String.format("%03d", page.number)
         val tmpFile = tmpDir.findFile("$filename.tmp")
@@ -317,26 +323,27 @@ class Downloader(
         val imageFile = tmpDir.listFiles()!!.find { it.name!!.startsWith("$filename.") }
 
         // If the image is already downloaded, do nothing. Otherwise download from network
-        val pageObservable = if (imageFile != null)
+        val pageObservable = if (imageFile != null) {
             Observable.just(imageFile)
-        else
+        } else {
             downloadImage(page, download.source, tmpDir, filename)
+        }
 
         return pageObservable
-                // When the image is ready, set image path, progress (just in case) and status
-                .doOnNext { file ->
-                    page.uri = file.uri
-                    page.progress = 100
-                    download.downloadedImages++
-                    page.status = Page.READY
-                }
-                .map { page }
-                // Mark this page as error and allow to download the remaining
-                .onErrorReturn {
-                    page.progress = 0
-                    page.status = Page.ERROR
-                    page
-                }
+            // When the image is ready, set image path, progress (just in case) and status
+            .doOnNext { file ->
+                page.uri = file.uri
+                page.progress = 100
+                download.downloadedImages++
+                page.status = Page.READY
+            }
+            .map { page }
+            // Mark this page as error and allow to download the remaining
+            .onErrorReturn {
+                page.progress = 0
+                page.status = Page.ERROR
+                page
+            }
     }
 
     /**
@@ -351,21 +358,21 @@ class Downloader(
         page.status = Page.DOWNLOAD_IMAGE
         page.progress = 0
         return source.fetchImage(page)
-                .map { response ->
-                    val file = tmpDir.createFile("$filename.tmp")
-                    try {
-                        response.body!!.source().saveTo(file.openOutputStream())
-                        val extension = getImageExtension(response, file)
-                        file.renameTo("$filename.$extension")
-                    } catch (e: Exception) {
-                        response.close()
-                        file.delete()
-                        throw e
-                    }
-                    file
+            .map { response ->
+                val file = tmpDir.createFile("$filename.tmp")
+                try {
+                    response.body!!.source().saveTo(file.openOutputStream())
+                    val extension = getImageExtension(response, file)
+                    file.renameTo("$filename.$extension")
+                } catch (e: Exception) {
+                    response.close()
+                    file.delete()
+                    throw e
                 }
-                // Retry 3 times, waiting 2, 4 and 8 seconds between attempts.
-                .retryWhen(RetryWithDelay(3, { (2 shl it - 1) * 1000 }, Schedulers.trampoline()))
+                file
+            }
+            // Retry 3 times, waiting 2, 4 and 8 seconds between attempts.
+            .retryWhen(RetryWithDelay(3, { (2 shl it - 1) * 1000 }, Schedulers.trampoline()))
     }
 
     /**
@@ -378,10 +385,10 @@ class Downloader(
     private fun getImageExtension(response: Response, file: UniFile): String {
         // Read content type if available.
         val mime = response.body?.contentType()?.let { ct -> "${ct.type}/${ct.subtype}" }
-                // Else guess from the uri.
-                ?: context.contentResolver.getType(file.uri)
-                // Else read magic numbers.
-                ?: ImageUtil.findImageType { file.openInputStream() }?.mime
+            // Else guess from the uri.
+            ?: context.contentResolver.getType(file.uri)
+            // Else read magic numbers.
+            ?: ImageUtil.findImageType { file.openInputStream() }?.mime
 
         return MimeTypeMap.getSingleton().getExtensionFromMimeType(mime) ?: "jpg"
     }
@@ -400,7 +407,6 @@ class Downloader(
         tmpDir: UniFile,
         dirname: String
     ) {
-
         // Ensure that the chapter folder has all the images.
         val downloadedImages = tmpDir.listFiles().orEmpty().filterNot { it.name!!.endsWith(".tmp") }
 

+ 17 - 17
app/src/main/java/eu/kanade/tachiyomi/data/download/model/DownloadQueue.kt

@@ -70,13 +70,13 @@ class DownloadQueue(
     }
 
     fun getActiveDownloads(): Observable<Download> =
-            Observable.from(this).filter { download -> download.status == Download.DOWNLOADING }
+        Observable.from(this).filter { download -> download.status == Download.DOWNLOADING }
 
     fun getStatusObservable(): Observable<Download> = statusSubject.onBackpressureBuffer()
 
     fun getUpdatedObservable(): Observable<List<Download>> = updatedRelay.onBackpressureBuffer()
-            .startWith(Unit)
-            .map { this }
+        .startWith(Unit)
+        .map { this }
 
     private fun setPagesFor(download: Download) {
         if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
@@ -86,21 +86,21 @@ class DownloadQueue(
 
     fun getProgressObservable(): Observable<Download> {
         return statusSubject.onBackpressureBuffer()
-                .startWith(getActiveDownloads())
-                .flatMap { download ->
-                    if (download.status == Download.DOWNLOADING) {
-                        val pageStatusSubject = PublishSubject.create<Int>()
-                        setPagesSubject(download.pages, pageStatusSubject)
-                        return@flatMap pageStatusSubject
-                                .onBackpressureBuffer()
-                                .filter { it == Page.READY }
-                                .map { download }
-                    } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
-                        setPagesSubject(download.pages, null)
-                    }
-                    Observable.just(download)
+            .startWith(getActiveDownloads())
+            .flatMap { download ->
+                if (download.status == Download.DOWNLOADING) {
+                    val pageStatusSubject = PublishSubject.create<Int>()
+                    setPagesSubject(download.pages, pageStatusSubject)
+                    return@flatMap pageStatusSubject
+                        .onBackpressureBuffer()
+                        .filter { it == Page.READY }
+                        .map { download }
+                } else if (download.status == Download.DOWNLOADED || download.status == Download.ERROR) {
+                    setPagesSubject(download.pages, null)
                 }
-                .filter { it.status == Download.DOWNLOADING }
+                Observable.just(download)
+            }
+            .filter { it.status == Download.DOWNLOADING }
     }
 
     private fun setPagesSubject(pages: List<Page>?, subject: PublishSubject<Int>?) {

+ 28 - 25
app/src/main/java/eu/kanade/tachiyomi/data/glide/LibraryMangaUrlFetcher.kt

@@ -25,36 +25,39 @@ class LibraryMangaUrlFetcher(
 
     override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
         if (!file.exists()) {
-            networkFetcher.loadData(priority, object : DataFetcher.DataCallback<InputStream> {
-                override fun onDataReady(data: InputStream?) {
-                    if (data != null) {
-                        val tmpFile = File(file.path + ".tmp")
-                        try {
-                            // Retrieve destination stream, create parent folders if needed.
-                            val output = try {
-                                tmpFile.outputStream()
-                            } catch (e: FileNotFoundException) {
-                                tmpFile.parentFile.mkdirs()
-                                tmpFile.outputStream()
-                            }
+            networkFetcher.loadData(
+                priority,
+                object : DataFetcher.DataCallback<InputStream> {
+                    override fun onDataReady(data: InputStream?) {
+                        if (data != null) {
+                            val tmpFile = File(file.path + ".tmp")
+                            try {
+                                // Retrieve destination stream, create parent folders if needed.
+                                val output = try {
+                                    tmpFile.outputStream()
+                                } catch (e: FileNotFoundException) {
+                                    tmpFile.parentFile.mkdirs()
+                                    tmpFile.outputStream()
+                                }
 
-                            // Copy the file and rename to the original.
-                            data.use { output.use { data.copyTo(output) } }
-                            tmpFile.renameTo(file)
-                            loadFromFile(callback)
-                        } catch (e: Exception) {
-                            tmpFile.delete()
-                            callback.onLoadFailed(e)
+                                // Copy the file and rename to the original.
+                                data.use { output.use { data.copyTo(output) } }
+                                tmpFile.renameTo(file)
+                                loadFromFile(callback)
+                            } catch (e: Exception) {
+                                tmpFile.delete()
+                                callback.onLoadFailed(e)
+                            }
+                        } else {
+                            callback.onLoadFailed(Exception("Null data"))
                         }
-                    } else {
-                        callback.onLoadFailed(Exception("Null data"))
                     }
-                }
 
-                override fun onLoadFailed(e: Exception) {
-                    callback.onLoadFailed(e)
+                    override fun onLoadFailed(e: Exception) {
+                        callback.onLoadFailed(e)
+                    }
                 }
-            })
+            )
         } else {
             loadFromFile(callback)
         }

+ 9 - 4
app/src/main/java/eu/kanade/tachiyomi/data/glide/TachiGlideModule.kt

@@ -27,8 +27,10 @@ class TachiGlideModule : AppGlideModule() {
     override fun applyOptions(context: Context, builder: GlideBuilder) {
         builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024))
         builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))
-        builder.setDefaultTransitionOptions(Drawable::class.java,
-                DrawableTransitionOptions.withCrossFade())
+        builder.setDefaultTransitionOptions(
+            Drawable::class.java,
+            DrawableTransitionOptions.withCrossFade()
+        )
     }
 
     override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
@@ -36,7 +38,10 @@ class TachiGlideModule : AppGlideModule() {
 
         registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory)
         registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory())
-        registry.append(InputStream::class.java, InputStream::class.java, PassthroughModelLoader
-                .Factory())
+        registry.append(
+            InputStream::class.java, InputStream::class.java,
+            PassthroughModelLoader
+                .Factory()
+        )
     }
 }

+ 13 - 11
app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt

@@ -14,7 +14,7 @@ import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
 
 class LibraryUpdateJob(private val context: Context, workerParams: WorkerParameters) :
-        Worker(context, workerParams) {
+    Worker(context, workerParams) {
 
     override fun doWork(): Result {
         LibraryUpdateService.start(context)
@@ -30,22 +30,24 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
             if (interval > 0) {
                 val restrictions = preferences.libraryUpdateRestriction()!!
                 val acRestriction = "ac" in restrictions
-                val wifiRestriction = if ("wifi" in restrictions)
+                val wifiRestriction = if ("wifi" in restrictions) {
                     NetworkType.UNMETERED
-                else
+                } else {
                     NetworkType.CONNECTED
+                }
 
                 val constraints = Constraints.Builder()
-                        .setRequiredNetworkType(wifiRestriction)
-                        .setRequiresCharging(acRestriction)
-                        .build()
+                    .setRequiredNetworkType(wifiRestriction)
+                    .setRequiresCharging(acRestriction)
+                    .build()
 
                 val request = PeriodicWorkRequestBuilder<LibraryUpdateJob>(
-                        interval.toLong(), TimeUnit.HOURS,
-                        10, TimeUnit.MINUTES)
-                        .addTag(TAG)
-                        .setConstraints(constraints)
-                        .build()
+                    interval.toLong(), TimeUnit.HOURS,
+                    10, TimeUnit.MINUTES
+                )
+                    .addTag(TAG)
+                    .setConstraints(constraints)
+                    .build()
 
                 WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request)
             } else {

+ 5 - 4
app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt

@@ -8,8 +8,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 object LibraryUpdateRanker {
 
     val rankingScheme = listOf(
-            (this::lexicographicRanking)(),
-            (this::latestFirstRanking)())
+        (this::lexicographicRanking)(),
+        (this::latestFirstRanking)()
+    )
 
     /**
      * Provides a total ordering over all the Mangas.
@@ -22,7 +23,7 @@ object LibraryUpdateRanker {
      */
     fun latestFirstRanking(): Comparator<Manga> {
         return Comparator { mangaFirst: Manga,
-                            mangaSecond: Manga ->
+            mangaSecond: Manga ->
             compareValues(mangaSecond.last_update, mangaFirst.last_update)
         }
     }
@@ -35,7 +36,7 @@ object LibraryUpdateRanker {
      */
     fun lexicographicRanking(): Comparator<Manga> {
         return Comparator { mangaFirst: Manga,
-                            mangaSecond: Manga ->
+            mangaSecond: Manga ->
             compareValues(mangaFirst.title, mangaSecond.title)
         }
     }

+ 184 - 154
app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt

@@ -184,7 +184,8 @@ class LibraryUpdateService(
         super.onCreate()
         startForeground(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder.build())
         wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(
-                PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock")
+            PowerManager.PARTIAL_WAKE_LOCK, "LibraryUpdateService:WakeLock"
+        )
         wakeLock.acquire()
     }
 
@@ -218,33 +219,37 @@ class LibraryUpdateService(
     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
         if (intent == null) return START_NOT_STICKY
         val target = intent.getSerializableExtra(KEY_TARGET) as? Target
-                ?: return START_NOT_STICKY
+            ?: return START_NOT_STICKY
 
         // Unsubscribe from any previous subscription if needed.
         subscription?.unsubscribe()
 
         // Update favorite manga. Destroy service when completed or in case of an error.
         subscription = Observable
-                .defer {
-                    val selectedScheme = preferences.libraryUpdatePrioritization().get()
-                    val mangaList = getMangaToUpdate(intent, target)
-                            .sortedWith(rankingScheme[selectedScheme])
-
-                    // Update either chapter list or manga details.
-                    when (target) {
-                        Target.CHAPTERS -> updateChapterList(mangaList)
-                        Target.DETAILS -> updateDetails(mangaList)
-                        Target.TRACKING -> updateTrackings(mangaList)
-                    }
+            .defer {
+                val selectedScheme = preferences.libraryUpdatePrioritization().get()
+                val mangaList = getMangaToUpdate(intent, target)
+                    .sortedWith(rankingScheme[selectedScheme])
+
+                // Update either chapter list or manga details.
+                when (target) {
+                    Target.CHAPTERS -> updateChapterList(mangaList)
+                    Target.DETAILS -> updateDetails(mangaList)
+                    Target.TRACKING -> updateTrackings(mangaList)
                 }
-                .subscribeOn(Schedulers.io())
-                .subscribe({
-                }, {
+            }
+            .subscribeOn(Schedulers.io())
+            .subscribe(
+                {
+                },
+                {
                     Timber.e(it)
                     stopSelf(startId)
-                }, {
+                },
+                {
                     stopSelf(startId)
-                })
+                }
+            )
 
         return START_REDELIVER_INTENT
     }
@@ -259,16 +264,17 @@ class LibraryUpdateService(
     fun getMangaToUpdate(intent: Intent, target: Target): List<LibraryManga> {
         val categoryId = intent.getIntExtra(KEY_CATEGORY, -1)
 
-        var listToUpdate = if (categoryId != -1)
+        var listToUpdate = if (categoryId != -1) {
             db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId }
-        else {
+        } else {
             val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt)
-            if (categoriesToUpdate.isNotEmpty())
+            if (categoriesToUpdate.isNotEmpty()) {
                 db.getLibraryMangas().executeAsBlocking()
-                        .filter { it.category in categoriesToUpdate }
-                        .distinctBy { it.id }
-            else
+                    .filter { it.category in categoriesToUpdate }
+                    .distinctBy { it.id }
+            } else {
                 db.getLibraryMangas().executeAsBlocking().distinctBy { it.id }
+            }
         }
         if (target == Target.CHAPTERS && preferences.updateOnlyNonCompleted()) {
             listToUpdate = listToUpdate.filter { it.status != SManga.COMPLETED }
@@ -302,55 +308,57 @@ class LibraryUpdateService(
 
         // Emit each manga and update it sequentially.
         return Observable.from(mangaToUpdate)
-                // Notify manga that will update.
-                .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
-                // Update the chapters of the manga.
-                .concatMap { manga ->
-                    updateManga(manga)
-                            // If there's any error, return empty update and continue.
-                            .onErrorReturn {
-                                failedUpdates.add(manga)
-                                Pair(emptyList(), emptyList())
-                            }
-                            // Filter out mangas without new chapters (or failed).
-                            .filter { pair -> pair.first.isNotEmpty() }
-                            .doOnNext {
-                                if (downloadNew && (categoriesToDownload.isEmpty() ||
-                                                manga.category in categoriesToDownload)) {
-
-                                    downloadChapters(manga, it.first)
-                                    hasDownloads = true
-                                }
-                            }
-                            // Convert to the manga that contains new chapters.
-                            .map {
-                                Pair(
-                                        manga,
-                                        (it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray())
-                                )
-                            }
-                }
-                // Add manga with new chapters to the list.
-                .doOnNext { manga ->
-                    // Add to the list
-                    newUpdates.add(manga)
-                }
-                // Notify result of the overall update.
-                .doOnCompleted {
-                    if (newUpdates.isNotEmpty()) {
-                        showUpdateNotifications(newUpdates)
-                        if (downloadNew && hasDownloads) {
-                            DownloadService.start(this)
+            // Notify manga that will update.
+            .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
+            // Update the chapters of the manga.
+            .concatMap { manga ->
+                updateManga(manga)
+                    // If there's any error, return empty update and continue.
+                    .onErrorReturn {
+                        failedUpdates.add(manga)
+                        Pair(emptyList(), emptyList())
+                    }
+                    // Filter out mangas without new chapters (or failed).
+                    .filter { pair -> pair.first.isNotEmpty() }
+                    .doOnNext {
+                        if (downloadNew && (
+                            categoriesToDownload.isEmpty() ||
+                                manga.category in categoriesToDownload
+                            )
+                        ) {
+                            downloadChapters(manga, it.first)
+                            hasDownloads = true
                         }
                     }
-
-                    if (failedUpdates.isNotEmpty()) {
-                        Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
+                    // Convert to the manga that contains new chapters.
+                    .map {
+                        Pair(
+                            manga,
+                            (it.first.sortedByDescending { ch -> ch.source_order }.toTypedArray())
+                        )
                     }
+            }
+            // Add manga with new chapters to the list.
+            .doOnNext { manga ->
+                // Add to the list
+                newUpdates.add(manga)
+            }
+            // Notify result of the overall update.
+            .doOnCompleted {
+                if (newUpdates.isNotEmpty()) {
+                    showUpdateNotifications(newUpdates)
+                    if (downloadNew && hasDownloads) {
+                        DownloadService.start(this)
+                    }
+                }
 
-                    cancelProgressNotification()
+                if (failedUpdates.isNotEmpty()) {
+                    Timber.e("Failed updating: ${failedUpdates.map { it.title }}")
                 }
-                .map { manga -> manga.first }
+
+                cancelProgressNotification()
+            }
+            .map { manga -> manga.first }
     }
 
     fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
@@ -373,7 +381,7 @@ class LibraryUpdateService(
     fun updateManga(manga: Manga): Observable<Pair<List<Chapter>, List<Chapter>>> {
         val source = sourceManager.get(manga.source) as? HttpSource ?: return Observable.empty()
         return source.fetchChapterList(manga)
-                .map { syncChaptersWithSource(db, it, manga, source) }
+            .map { syncChaptersWithSource(db, it, manga, source) }
     }
 
     /**
@@ -389,24 +397,24 @@ class LibraryUpdateService(
 
         // Emit each manga and update it sequentially.
         return Observable.from(mangaToUpdate)
-                // Notify manga that will update.
-                .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
-                // Update the details of the manga.
-                .concatMap { manga ->
-                    val source = sourceManager.get(manga.source) as? HttpSource
-                            ?: return@concatMap Observable.empty<LibraryManga>()
-
-                    source.fetchMangaDetails(manga)
-                            .map { networkManga ->
-                                manga.copyFrom(networkManga)
-                                db.insertManga(manga).executeAsBlocking()
-                                manga
-                            }
-                            .onErrorReturn { manga }
-                }
-                .doOnCompleted {
-                    cancelProgressNotification()
-                }
+            // Notify manga that will update.
+            .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size) }
+            // Update the details of the manga.
+            .concatMap { manga ->
+                val source = sourceManager.get(manga.source) as? HttpSource
+                    ?: return@concatMap Observable.empty<LibraryManga>()
+
+                source.fetchMangaDetails(manga)
+                    .map { networkManga ->
+                        manga.copyFrom(networkManga)
+                        db.insertManga(manga).executeAsBlocking()
+                        manga
+                    }
+                    .onErrorReturn { manga }
+            }
+            .doOnCompleted {
+                cancelProgressNotification()
+            }
     }
 
     /**
@@ -421,28 +429,28 @@ class LibraryUpdateService(
 
         // Emit each manga and update it sequentially.
         return Observable.from(mangaToUpdate)
-                // Notify manga that will update.
-                .doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) }
-                // Update the tracking details.
-                .concatMap { manga ->
-                    val tracks = db.getTracks(manga).executeAsBlocking()
-
-                    Observable.from(tracks)
-                            .concatMap { track ->
-                                val service = trackManager.getService(track.sync_id)
-                                if (service != null && service in loggedServices) {
-                                    service.refresh(track)
-                                            .doOnNext { db.insertTrack(it).executeAsBlocking() }
-                                            .onErrorReturn { track }
-                                } else {
-                                    Observable.empty()
-                                }
-                            }
-                            .map { manga }
-                }
-                .doOnCompleted {
-                    cancelProgressNotification()
-                }
+            // Notify manga that will update.
+            .doOnNext { showProgressNotification(it, count++, mangaToUpdate.size) }
+            // Update the tracking details.
+            .concatMap { manga ->
+                val tracks = db.getTracks(manga).executeAsBlocking()
+
+                Observable.from(tracks)
+                    .concatMap { track ->
+                        val service = trackManager.getService(track.sync_id)
+                        if (service != null && service in loggedServices) {
+                            service.refresh(track)
+                                .doOnNext { db.insertTrack(it).executeAsBlocking() }
+                                .onErrorReturn { track }
+                        } else {
+                            Observable.empty()
+                        }
+                    }
+                    .map { manga }
+            }
+            .doOnCompleted {
+                cancelProgressNotification()
+            }
     }
 
     /**
@@ -453,15 +461,19 @@ class LibraryUpdateService(
      * @param total the total progress.
      */
     private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
-        val title = if (preferences.hideNotificationContent())
+        val title = if (preferences.hideNotificationContent()) {
             getString(R.string.notification_check_updates)
-        else
+        } else {
             manga.title
+        }
 
-        notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotificationBuilder
+        notificationManager.notify(
+            Notifications.ID_LIBRARY_PROGRESS,
+            progressNotificationBuilder
                 .setContentTitle(title)
                 .setProgress(total, current, false)
-                .build())
+                .build()
+        )
     }
 
     /**
@@ -476,31 +488,38 @@ class LibraryUpdateService(
 
         NotificationManagerCompat.from(this).apply {
             // Parent group notification
-            notify(Notifications.ID_NEW_CHAPTERS, notification(Notifications.CHANNEL_NEW_CHAPTERS) {
-                setContentTitle(getString(R.string.notification_new_chapters))
-                if (updates.size == 1 && !preferences.hideNotificationContent()) {
-                    setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
-                } else {
-                    setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
-
-                    if (!preferences.hideNotificationContent()) {
-                        setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") {
-                            it.first.title.chop(NOTIF_TITLE_MAX_LEN)
-                        }))
+            notify(
+                Notifications.ID_NEW_CHAPTERS,
+                notification(Notifications.CHANNEL_NEW_CHAPTERS) {
+                    setContentTitle(getString(R.string.notification_new_chapters))
+                    if (updates.size == 1 && !preferences.hideNotificationContent()) {
+                        setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
+                    } else {
+                        setContentText(resources.getQuantityString(R.plurals.notification_new_chapters_summary, updates.size, updates.size))
+
+                        if (!preferences.hideNotificationContent()) {
+                            setStyle(
+                                NotificationCompat.BigTextStyle().bigText(
+                                    updates.joinToString("\n") {
+                                        it.first.title.chop(NOTIF_TITLE_MAX_LEN)
+                                    }
+                                )
+                            )
+                        }
                     }
-                }
 
-                setSmallIcon(R.drawable.ic_tachi)
-                setLargeIcon(notificationBitmap)
+                    setSmallIcon(R.drawable.ic_tachi)
+                    setLargeIcon(notificationBitmap)
 
-                setGroup(Notifications.GROUP_NEW_CHAPTERS)
-                setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
-                setGroupSummary(true)
-                priority = NotificationCompat.PRIORITY_HIGH
+                    setGroup(Notifications.GROUP_NEW_CHAPTERS)
+                    setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
+                    setGroupSummary(true)
+                    priority = NotificationCompat.PRIORITY_HIGH
 
-                setContentIntent(getNotificationIntent())
-                setAutoCancel(true)
-            })
+                    setContentIntent(getNotificationIntent())
+                    setAutoCancel(true)
+                }
+            )
 
             // Per-manga notification
             if (!preferences.hideNotificationContent()) {
@@ -536,13 +555,21 @@ class LibraryUpdateService(
             setAutoCancel(true)
 
             // Mark chapters as read action
-            addAction(R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
-                    NotificationReceiver.markAsReadPendingBroadcast(this@LibraryUpdateService,
-                            manga, chapters, Notifications.ID_NEW_CHAPTERS))
+            addAction(
+                R.drawable.ic_glasses_black_24dp, getString(R.string.action_mark_as_read),
+                NotificationReceiver.markAsReadPendingBroadcast(
+                    this@LibraryUpdateService,
+                    manga, chapters, Notifications.ID_NEW_CHAPTERS
+                )
+            )
             // View chapters action
-            addAction(R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
-                    NotificationReceiver.openChapterPendingActivity(this@LibraryUpdateService,
-                            manga, Notifications.ID_NEW_CHAPTERS))
+            addAction(
+                R.drawable.ic_book_24dp, getString(R.string.action_view_chapters),
+                NotificationReceiver.openChapterPendingActivity(
+                    this@LibraryUpdateService,
+                    manga, Notifications.ID_NEW_CHAPTERS
+                )
+            )
         }
     }
 
@@ -556,28 +583,31 @@ class LibraryUpdateService(
     private fun getMangaIcon(manga: Manga): Bitmap? {
         return try {
             Glide.with(this)
-                    .asBitmap()
-                    .load(manga.toMangaThumbnail())
-                    .dontTransform()
-                    .centerCrop()
-                    .circleCrop()
-                    .override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE)
-                    .submit()
-                    .get()
+                .asBitmap()
+                .load(manga.toMangaThumbnail())
+                .dontTransform()
+                .centerCrop()
+                .circleCrop()
+                .override(NOTIF_ICON_SIZE, NOTIF_ICON_SIZE)
+                .submit()
+                .get()
         } catch (e: Exception) {
             null
         }
     }
 
     private fun getNewChaptersDescription(chapters: Array<Chapter>): String {
-        val formatter = DecimalFormat("#.###", DecimalFormatSymbols()
-                .apply { decimalSeparator = '.' })
+        val formatter = DecimalFormat(
+            "#.###",
+            DecimalFormatSymbols()
+                .apply { decimalSeparator = '.' }
+        )
 
         val displayableChapterNumbers = chapters
-                .filter { it.isRecognizedNumber }
-                .sortedBy { it.chapter_number }
-                .map { formatter.format(it.chapter_number) }
-                .toSet()
+            .filter { it.isRecognizedNumber }
+            .sortedBy { it.chapter_number }
+            .map { formatter.format(it.chapter_number) }
+            .toSet()
 
         return when (displayableChapterNumbers.size) {
             // No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)

+ 38 - 25
app/src/main/java/eu/kanade/tachiyomi/data/notification/NotificationReceiver.kt

@@ -54,22 +54,35 @@ class NotificationReceiver : BroadcastReceiver() {
             // Clear the download queue
             ACTION_CLEAR_DOWNLOADS -> downloadManager.clearQueue(true)
             // Launch share activity and dismiss notification
-            ACTION_SHARE_IMAGE -> shareImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
-                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
+            ACTION_SHARE_IMAGE ->
+                shareImage(
+                    context, intent.getStringExtra(EXTRA_FILE_LOCATION),
+                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
+                )
             // Delete image from path and dismiss notification
-            ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
-                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
+            ACTION_DELETE_IMAGE ->
+                deleteImage(
+                    context, intent.getStringExtra(EXTRA_FILE_LOCATION),
+                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
+                )
             // Share backup file
-            ACTION_SHARE_BACKUP -> shareBackup(context, intent.getParcelableExtra(EXTRA_URI),
-                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
-            ACTION_CANCEL_RESTORE -> cancelRestore(context,
-                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
+            ACTION_SHARE_BACKUP ->
+                shareBackup(
+                    context, intent.getParcelableExtra(EXTRA_URI),
+                    intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
+                )
+            ACTION_CANCEL_RESTORE -> cancelRestore(
+                context,
+                intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)
+            )
             // Cancel library update and dismiss notification
             ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
             // Open reader activity
             ACTION_OPEN_CHAPTER -> {
-                openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
-                        intent.getLongExtra(EXTRA_CHAPTER_ID, -1))
+                openChapter(
+                    context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
+                    intent.getLongExtra(EXTRA_CHAPTER_ID, -1)
+                )
             }
             // Mark updated manga chapters as read
             ACTION_MARK_AS_READ -> {
@@ -208,19 +221,19 @@ class NotificationReceiver : BroadcastReceiver() {
 
         launchIO {
             chapterUrls.mapNotNull { db.getChapter(it, mangaId).executeAsBlocking() }
-                    .forEach {
-                        it.read = true
-                        db.updateChapterProgress(it).executeAsBlocking()
-                        if (preferences.removeAfterMarkedAsRead()) {
-                            val manga = db.getManga(mangaId).executeAsBlocking()
-                            if (manga != null) {
-                                val source = sourceManager.get(manga.source)
-                                if (source != null) {
-                                    downloadManager.deleteChapters(listOf(it), manga, source)
-                                }
+                .forEach {
+                    it.read = true
+                    db.updateChapterProgress(it).executeAsBlocking()
+                    if (preferences.removeAfterMarkedAsRead()) {
+                        val manga = db.getManga(mangaId).executeAsBlocking()
+                        if (manga != null) {
+                            val source = sourceManager.get(manga.source)
+                            if (source != null) {
+                                downloadManager.deleteChapters(listOf(it), manga, source)
                             }
                         }
                     }
+                }
         }
     }
 
@@ -427,11 +440,11 @@ class NotificationReceiver : BroadcastReceiver() {
          */
         internal fun openChapterPendingActivity(context: Context, manga: Manga, groupId: Int): PendingIntent {
             val newIntent =
-                    Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA)
-                            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
-                            .putExtra(MangaController.MANGA_EXTRA, manga.id)
-                            .putExtra("notificationId", manga.id.hashCode())
-                            .putExtra("groupId", groupId)
+                Intent(context, MainActivity::class.java).setAction(MainActivity.SHORTCUT_MANGA)
+                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+                    .putExtra(MangaController.MANGA_EXTRA, manga.id)
+                    .putExtra("notificationId", manga.id.hashCode())
+                    .putExtra("groupId", groupId)
             return PendingIntent.getActivity(context, manga.id.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT)
         }
 

+ 30 - 18
app/src/main/java/eu/kanade/tachiyomi/data/notification/Notifications.kt

@@ -61,24 +61,36 @@ object Notifications {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
 
         val channels = listOf(
-                NotificationChannel(CHANNEL_COMMON, context.getString(R.string.channel_common),
-                        NotificationManager.IMPORTANCE_LOW),
-                NotificationChannel(CHANNEL_LIBRARY, context.getString(R.string.channel_library),
-                        NotificationManager.IMPORTANCE_LOW).apply {
-                    setShowBadge(false)
-                },
-                NotificationChannel(CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
-                        NotificationManager.IMPORTANCE_LOW).apply {
-                    setShowBadge(false)
-                },
-                NotificationChannel(CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
-                        NotificationManager.IMPORTANCE_DEFAULT),
-                NotificationChannel(CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates),
-                        NotificationManager.IMPORTANCE_DEFAULT),
-                NotificationChannel(CHANNEL_BACKUP_RESTORE, context.getString(R.string.channel_backup_restore),
-                    NotificationManager.IMPORTANCE_HIGH).apply {
-                    setShowBadge(false)
-                }
+            NotificationChannel(
+                CHANNEL_COMMON, context.getString(R.string.channel_common),
+                NotificationManager.IMPORTANCE_LOW
+            ),
+            NotificationChannel(
+                CHANNEL_LIBRARY, context.getString(R.string.channel_library),
+                NotificationManager.IMPORTANCE_LOW
+            ).apply {
+                setShowBadge(false)
+            },
+            NotificationChannel(
+                CHANNEL_DOWNLOADER, context.getString(R.string.channel_downloader),
+                NotificationManager.IMPORTANCE_LOW
+            ).apply {
+                setShowBadge(false)
+            },
+            NotificationChannel(
+                CHANNEL_NEW_CHAPTERS, context.getString(R.string.channel_new_chapters),
+                NotificationManager.IMPORTANCE_DEFAULT
+            ),
+            NotificationChannel(
+                CHANNEL_UPDATES_TO_EXTS, context.getString(R.string.channel_ext_updates),
+                NotificationManager.IMPORTANCE_DEFAULT
+            ),
+            NotificationChannel(
+                CHANNEL_BACKUP_RESTORE, context.getString(R.string.channel_backup_restore),
+                NotificationManager.IMPORTANCE_HIGH
+            ).apply {
+                setShowBadge(false)
+            }
         )
         context.notificationManager.createNotificationChannels(channels)
     }

+ 15 - 7
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -45,12 +45,20 @@ class PreferencesHelper(val context: Context) {
     private val flowPrefs = FlowSharedPreferences(prefs)
 
     private val defaultDownloadsDir = Uri.fromFile(
-            File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
-                    context.getString(R.string.app_name), "downloads"))
+        File(
+            Environment.getExternalStorageDirectory().absolutePath + File.separator +
+                context.getString(R.string.app_name),
+            "downloads"
+        )
+    )
 
     private val defaultBackupDir = Uri.fromFile(
-            File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
-                    context.getString(R.string.app_name), "backup"))
+        File(
+            Environment.getExternalStorageDirectory().absolutePath + File.separator +
+                context.getString(R.string.app_name),
+            "backup"
+        )
+    )
 
     fun startScreen() = prefs.getInt(Keys.startScreen, 1)
 
@@ -148,9 +156,9 @@ class PreferencesHelper(val context: Context) {
 
     fun setTrackCredentials(sync: TrackService, username: String, password: String) {
         prefs.edit()
-                .putString(Keys.trackUsername(sync.id), username)
-                .putString(Keys.trackPassword(sync.id), password)
-                .apply()
+            .putString(Keys.trackUsername(sync.id), username)
+            .putString(Keys.trackPassword(sync.id), password)
+            .apply()
     }
 
     fun trackToken(sync: TrackService) = flowPrefs.getString(Keys.trackToken(sync.id), "")

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt

@@ -63,7 +63,7 @@ abstract class TrackService(val id: Int) {
 
     open val isLogged: Boolean
         get() = getUsername().isNotEmpty() &&
-                getPassword().isNotEmpty()
+            getPassword().isNotEmpty()
 
     fun getUsername() = preferences.trackUsername(this)!!
 

+ 16 - 16
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt

@@ -150,18 +150,18 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
 
     override fun bind(track: Track): Observable<Track> {
         return api.findLibManga(track, getUsername().toInt())
-                .flatMap { remoteTrack ->
-                    if (remoteTrack != null) {
-                        track.copyPersonalFrom(remoteTrack)
-                        track.library_id = remoteTrack.library_id
-                        update(track)
-                    } else {
-                        // Set default fields if it's not found in the list
-                        track.score = DEFAULT_SCORE.toFloat()
-                        track.status = DEFAULT_STATUS
-                        add(track)
-                    }
+            .flatMap { remoteTrack ->
+                if (remoteTrack != null) {
+                    track.copyPersonalFrom(remoteTrack)
+                    track.library_id = remoteTrack.library_id
+                    update(track)
+                } else {
+                    // Set default fields if it's not found in the list
+                    track.score = DEFAULT_SCORE.toFloat()
+                    track.status = DEFAULT_STATUS
+                    add(track)
                 }
+            }
     }
 
     override fun search(query: String): Observable<List<TrackSearch>> {
@@ -170,11 +170,11 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
 
     override fun refresh(track: Track): Observable<Track> {
         return api.getLibManga(track, getUsername().toInt())
-                .map { remoteTrack ->
-                    track.copyPersonalFrom(remoteTrack)
-                    track.total_chapters = remoteTrack.total_chapters
-                    track
-                }
+            .map { remoteTrack ->
+                track.copyPersonalFrom(remoteTrack)
+                track.total_chapters = remoteTrack.total_chapters
+                track
+            }
     }
 
     override fun login(username: String, password: String) = login(password)

+ 109 - 97
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt

@@ -25,7 +25,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
     private val authClient = client.newBuilder().addInterceptor(interceptor).build()
 
     fun addLibManga(track: Track): Observable<Track> {
-        val query = """
+        val query =
+            """
             |mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
                 |SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) { 
                 |   id 
@@ -34,35 +35,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
             |}
             |""".trimMargin()
         val variables = jsonObject(
-                "mangaId" to track.media_id,
-                "progress" to track.last_chapter_read,
-                "status" to track.toAnilistStatus()
+            "mangaId" to track.media_id,
+            "progress" to track.last_chapter_read,
+            "status" to track.toAnilistStatus()
         )
         val payload = jsonObject(
-                "query" to query,
-                "variables" to variables
+            "query" to query,
+            "variables" to variables
         )
         val body = payload.toString().toRequestBody(jsonMime)
         val request = Request.Builder()
-                .url(apiUrl)
-                .post(body)
-                .build()
+            .url(apiUrl)
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    netResponse.close()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    val response = JsonParser.parseString(responseBody).obj
-                    track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong
-                    track
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                netResponse.close()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                val response = JsonParser.parseString(responseBody).obj
+                track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong
+                track
+            }
     }
 
     fun updateLibManga(track: Track): Observable<Track> {
-        val query = """
+        val query =
+            """
             |mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
                 |SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
                     |id
@@ -72,29 +74,30 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
             |}
             |""".trimMargin()
         val variables = jsonObject(
-                "listId" to track.library_id,
-                "progress" to track.last_chapter_read,
-                "status" to track.toAnilistStatus(),
-                "score" to track.score.toInt()
+            "listId" to track.library_id,
+            "progress" to track.last_chapter_read,
+            "status" to track.toAnilistStatus(),
+            "score" to track.score.toInt()
         )
         val payload = jsonObject(
-                "query" to query,
-                "variables" to variables
+            "query" to query,
+            "variables" to variables
         )
         val body = payload.toString().toRequestBody(jsonMime)
         val request = Request.Builder()
-                .url(apiUrl)
-                .post(body)
-                .build()
+            .url(apiUrl)
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map {
-                    track
-                }
+            .asObservableSuccess()
+            .map {
+                track
+            }
     }
 
     fun search(search: String): Observable<List<TrackSearch>> {
-        val query = """
+        val query =
+            """
             |query Search(${'$'}query: String) {
                 |Page (perPage: 50) {
                     |media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
@@ -119,35 +122,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
             |}
             |""".trimMargin()
         val variables = jsonObject(
-                "query" to search
+            "query" to search
         )
         val payload = jsonObject(
-                "query" to query,
-                "variables" to variables
+            "query" to query,
+            "variables" to variables
         )
         val body = payload.toString().toRequestBody(jsonMime)
         val request = Request.Builder()
-                .url(apiUrl)
-                .post(body)
-                .build()
+            .url(apiUrl)
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    val response = JsonParser.parseString(responseBody).obj
-                    val data = response["data"]!!.obj
-                    val page = data["Page"].obj
-                    val media = page["media"].array
-                    val entries = media.map { jsonToALManga(it.obj) }
-                    entries.map { it.toTrack() }
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                val response = JsonParser.parseString(responseBody).obj
+                val data = response["data"]!!.obj
+                val page = data["Page"].obj
+                val media = page["media"].array
+                val entries = media.map { jsonToALManga(it.obj) }
+                entries.map { it.toTrack() }
+            }
     }
 
     fun findLibManga(track: Track, userid: Int): Observable<Track?> {
-        val query = """
+        val query =
+            """
             |query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
                 |Page {
                     |mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
@@ -178,37 +182,37 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
             |}
             |""".trimMargin()
         val variables = jsonObject(
-                "id" to userid,
-                "manga_id" to track.media_id
+            "id" to userid,
+            "manga_id" to track.media_id
         )
         val payload = jsonObject(
-                "query" to query,
-                "variables" to variables
+            "query" to query,
+            "variables" to variables
         )
         val body = payload.toString().toRequestBody(jsonMime)
         val request = Request.Builder()
-                .url(apiUrl)
-                .post(body)
-                .build()
+            .url(apiUrl)
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    val response = JsonParser.parseString(responseBody).obj
-                    val data = response["data"]!!.obj
-                    val page = data["Page"].obj
-                    val media = page["mediaList"].array
-                    val entries = media.map { jsonToALUserManga(it.obj) }
-                    entries.firstOrNull()?.toTrack()
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                val response = JsonParser.parseString(responseBody).obj
+                val data = response["data"]!!.obj
+                val page = data["Page"].obj
+                val media = page["mediaList"].array
+                val entries = media.map { jsonToALUserManga(it.obj) }
+                entries.firstOrNull()?.toTrack()
+            }
     }
 
     fun getLibManga(track: Track, userid: Int): Observable<Track> {
         return findLibManga(track, userid)
-                .map { it ?: throw Exception("Could not find manga") }
+            .map { it ?: throw Exception("Could not find manga") }
     }
 
     fun createOAuth(token: String): OAuth {
@@ -216,7 +220,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
     }
 
     fun getCurrentUser(): Observable<Pair<Int, String>> {
-        val query = """
+        val query =
+            """
             |query User {
                 |Viewer {
                     |id
@@ -227,41 +232,48 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
             |}
             |""".trimMargin()
         val payload = jsonObject(
-                "query" to query
+            "query" to query
         )
         val body = payload.toString().toRequestBody(jsonMime)
         val request = Request.Builder()
-                .url(apiUrl)
-                .post(body)
-                .build()
+            .url(apiUrl)
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    val response = JsonParser.parseString(responseBody).obj
-                    val data = response["data"]!!.obj
-                    val viewer = data["Viewer"].obj
-                    Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString)
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                val response = JsonParser.parseString(responseBody).obj
+                val data = response["data"]!!.obj
+                val viewer = data["Viewer"].obj
+                Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString)
+            }
     }
 
     private fun jsonToALManga(struct: JsonObject): ALManga {
         val date = try {
             val date = Calendar.getInstance()
-            date.set(struct["startDate"]["year"].nullInt ?: 0, (struct["startDate"]["month"].nullInt
-                    ?: 0) - 1,
-                    struct["startDate"]["day"].nullInt ?: 0)
+            date.set(
+                struct["startDate"]["year"].nullInt ?: 0,
+                (
+                    struct["startDate"]["month"].nullInt
+                        ?: 0
+                    ) - 1,
+                struct["startDate"]["day"].nullInt ?: 0
+            )
             date.timeInMillis
         } catch (_: Exception) {
             0L
         }
 
-        return ALManga(struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
-                struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
-                date, struct["chapters"].nullInt ?: 0)
+        return ALManga(
+            struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
+            struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
+            date, struct["chapters"].nullInt ?: 0
+        )
     }
 
     private fun jsonToALUserManga(struct: JsonObject): ALUserManga {
@@ -280,8 +292,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
         }
 
         fun authUrl() = Uri.parse("${baseUrl}oauth/authorize").buildUpon()
-                .appendQueryParameter("client_id", clientId)
-                .appendQueryParameter("response_type", "token")
-                .build()
+            .appendQueryParameter("client_id", clientId)
+            .appendQueryParameter("response_type", "token")
+            .build()
     }
 }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt

@@ -38,8 +38,8 @@ class AnilistInterceptor(val anilist: Anilist, private var token: String?) : Int
 
         // Add the authorization header to the original request.
         val authRequest = originalRequest.newBuilder()
-                .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
-                .build()
+            .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
+            .build()
 
         return chain.proceed(authRequest)
     }

+ 26 - 26
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/Bangumi.kt

@@ -39,23 +39,23 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
 
     override fun bind(track: Track): Observable<Track> {
         return api.statusLibManga(track)
-                .flatMap {
-                    api.findLibManga(track).flatMap { remoteTrack ->
-                        if (remoteTrack != null && it != null) {
-                            track.copyPersonalFrom(remoteTrack)
-                            track.library_id = remoteTrack.library_id
-                            track.status = remoteTrack.status
-                            track.last_chapter_read = remoteTrack.last_chapter_read
-                            refresh(track)
-                        } else {
-                            // Set default fields if it's not found in the list
-                            track.score = DEFAULT_SCORE.toFloat()
-                            track.status = DEFAULT_STATUS
-                            add(track)
-                            update(track)
-                        }
+            .flatMap {
+                api.findLibManga(track).flatMap { remoteTrack ->
+                    if (remoteTrack != null && it != null) {
+                        track.copyPersonalFrom(remoteTrack)
+                        track.library_id = remoteTrack.library_id
+                        track.status = remoteTrack.status
+                        track.last_chapter_read = remoteTrack.last_chapter_read
+                        refresh(track)
+                    } else {
+                        // Set default fields if it's not found in the list
+                        track.score = DEFAULT_SCORE.toFloat()
+                        track.status = DEFAULT_STATUS
+                        add(track)
+                        update(track)
                     }
                 }
+            }
     }
 
     override fun search(query: String): Observable<List<TrackSearch>> {
@@ -64,17 +64,17 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
 
     override fun refresh(track: Track): Observable<Track> {
         return api.statusLibManga(track)
-                .flatMap {
-                    track.copyPersonalFrom(it!!)
-                    api.findLibManga(track)
-                            .map { remoteTrack ->
-                                if (remoteTrack != null) {
-                                    track.total_chapters = remoteTrack.total_chapters
-                                    track.status = remoteTrack.status
-                                }
-                                track
-                            }
-                }
+            .flatMap {
+                track.copyPersonalFrom(it!!)
+                api.findLibManga(track)
+                    .map { remoteTrack ->
+                        if (remoteTrack != null) {
+                            track.total_chapters = remoteTrack.total_chapters
+                            track.status = remoteTrack.status
+                        }
+                        track
+                    }
+            }
     }
 
     override fun getLogo() = R.drawable.ic_tracker_bangumi

+ 103 - 93
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiApi.kt

@@ -26,73 +26,74 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
 
     fun addLibManga(track: Track): Observable<Track> {
         val body = FormBody.Builder()
-                .add("rating", track.score.toInt().toString())
-                .add("status", track.toBangumiStatus())
-                .build()
+            .add("rating", track.score.toInt().toString())
+            .add("status", track.toBangumiStatus())
+            .build()
         val request = Request.Builder()
-                .url("$apiUrl/collection/${track.media_id}/update")
-                .post(body)
-                .build()
+            .url("$apiUrl/collection/${track.media_id}/update")
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map {
-                    track
-                }
+            .asObservableSuccess()
+            .map {
+                track
+            }
     }
 
     fun updateLibManga(track: Track): Observable<Track> {
         // chapter update
         val body = FormBody.Builder()
-                .add("watched_eps", track.last_chapter_read.toString())
-                .build()
+            .add("watched_eps", track.last_chapter_read.toString())
+            .build()
         val request = Request.Builder()
-                .url("$apiUrl/subject/${track.media_id}/update/watched_eps")
-                .post(body)
-                .build()
+            .url("$apiUrl/subject/${track.media_id}/update/watched_eps")
+            .post(body)
+            .build()
 
         // read status update
         val sbody = FormBody.Builder()
-                .add("status", track.toBangumiStatus())
-                .build()
+            .add("status", track.toBangumiStatus())
+            .build()
         val srequest = Request.Builder()
-                .url("$apiUrl/collection/${track.media_id}/update")
-                .post(sbody)
-                .build()
+            .url("$apiUrl/collection/${track.media_id}/update")
+            .post(sbody)
+            .build()
         return authClient.newCall(srequest)
-                .asObservableSuccess()
-                .map {
-                    track
-                }.flatMap {
-                    authClient.newCall(request)
-                            .asObservableSuccess()
-                            .map {
-                                track
-                            }
-                }
+            .asObservableSuccess()
+            .map {
+                track
+            }.flatMap {
+                authClient.newCall(request)
+                    .asObservableSuccess()
+                    .map {
+                        track
+                    }
+            }
     }
 
     fun search(search: String): Observable<List<TrackSearch>> {
         val url = Uri.parse(
-                "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}").buildUpon()
-                .appendQueryParameter("max_results", "20")
-                .build()
+            "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}"
+        ).buildUpon()
+            .appendQueryParameter("max_results", "20")
+            .build()
         val request = Request.Builder()
-                .url(url.toString())
-                .get()
-                .build()
+            .url(url.toString())
+            .get()
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    var responseBody = netResponse.body?.string().orEmpty()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    if (responseBody.contains("\"code\":404")) {
-                        responseBody = "{\"results\":0,\"list\":[]}"
-                    }
-                    val response = JsonParser.parseString(responseBody).obj["list"]?.array
-                    response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) }
+            .asObservableSuccess()
+            .map { netResponse ->
+                var responseBody = netResponse.body?.string().orEmpty()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                if (responseBody.contains("\"code\":404")) {
+                    responseBody = "{\"results\":0,\"list\":[]}"
+                }
+                val response = JsonParser.parseString(responseBody).obj["list"]?.array
+                response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) }
+            }
     }
 
     private fun jsonToSearch(obj: JsonObject): TrackSearch {
@@ -109,9 +110,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
         return Track.create(TrackManager.BANGUMI).apply {
             title = mangas["name"].asString
             media_id = mangas["id"].asInt
-            score = if (mangas["rating"] != null)
-                (if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f)
-            else 0f
+            score = if (mangas["rating"] != null) {
+                if (mangas["rating"].isJsonObject) {
+                    mangas["rating"].obj["score"].asFloat
+                } else {
+                    0f
+                }
+            } else {
+                0f
+            }
             status = Bangumi.DEFAULT_STATUS
             tracking_url = mangas["url"].asString
         }
@@ -120,37 +127,37 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
     fun findLibManga(track: Track): Observable<Track?> {
         val urlMangas = "$apiUrl/subject/${track.media_id}"
         val requestMangas = Request.Builder()
-                .url(urlMangas)
-                .get()
-                .build()
+            .url(urlMangas)
+            .get()
+            .build()
 
         return authClient.newCall(requestMangas)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    // get comic info
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    jsonToTrack(JsonParser.parseString(responseBody).obj)
-                }
+            .asObservableSuccess()
+            .map { netResponse ->
+                // get comic info
+                val responseBody = netResponse.body?.string().orEmpty()
+                jsonToTrack(JsonParser.parseString(responseBody).obj)
+            }
     }
 
     fun statusLibManga(track: Track): Observable<Track?> {
         val urlUserRead = "$apiUrl/collection/${track.media_id}"
         val requestUserRead = Request.Builder()
-                .url(urlUserRead)
-                .cacheControl(CacheControl.FORCE_NETWORK)
-                .get()
-                .build()
+            .url(urlUserRead)
+            .cacheControl(CacheControl.FORCE_NETWORK)
+            .get()
+            .build()
 
         // todo get user readed chapter here
         return authClient.newCall(requestUserRead)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val resp = netResponse.body?.string()
-                    val coll = gson.fromJson(resp, Collection::class.java)
-                    track.status = coll.status?.id!!
-                    track.last_chapter_read = coll.ep_status!!
-                    track
-                }
+            .asObservableSuccess()
+            .map { netResponse ->
+                val resp = netResponse.body?.string()
+                val coll = gson.fromJson(resp, Collection::class.java)
+                track.status = coll.status?.id!!
+                track.last_chapter_read = coll.ep_status!!
+                track
+            }
     }
 
     fun accessToken(code: String): Observable<OAuth> {
@@ -163,14 +170,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
         }
     }
 
-    private fun accessTokenRequest(code: String) = POST(oauthUrl,
-            body = FormBody.Builder()
-                    .add("grant_type", "authorization_code")
-                    .add("client_id", clientId)
-                    .add("client_secret", clientSecret)
-                    .add("code", code)
-                    .add("redirect_uri", redirectUrl)
-                    .build()
+    private fun accessTokenRequest(code: String) = POST(
+        oauthUrl,
+        body = FormBody.Builder()
+            .add("grant_type", "authorization_code")
+            .add("client_id", clientId)
+            .add("client_secret", clientSecret)
+            .add("code", code)
+            .add("redirect_uri", redirectUrl)
+            .build()
     )
 
     companion object {
@@ -190,19 +198,21 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
         }
 
         fun authUrl() =
-                Uri.parse(loginUrl).buildUpon()
-                        .appendQueryParameter("client_id", clientId)
-                        .appendQueryParameter("response_type", "code")
-                        .appendQueryParameter("redirect_uri", redirectUrl)
-                        .build()
-
-        fun refreshTokenRequest(token: String) = POST(oauthUrl,
-                body = FormBody.Builder()
-                        .add("grant_type", "refresh_token")
-                        .add("client_id", clientId)
-                        .add("client_secret", clientSecret)
-                        .add("refresh_token", token)
-                        .add("redirect_uri", redirectUrl)
-                        .build())
+            Uri.parse(loginUrl).buildUpon()
+                .appendQueryParameter("client_id", clientId)
+                .appendQueryParameter("response_type", "code")
+                .appendQueryParameter("redirect_uri", redirectUrl)
+                .build()
+
+        fun refreshTokenRequest(token: String) = POST(
+            oauthUrl,
+            body = FormBody.Builder()
+                .add("grant_type", "refresh_token")
+                .add("client_id", clientId)
+                .add("client_secret", clientSecret)
+                .add("refresh_token", token)
+                .add("redirect_uri", redirectUrl)
+                .build()
+        )
     }
 }

+ 16 - 13
app/src/main/java/eu/kanade/tachiyomi/data/track/bangumi/BangumiInterceptor.kt

@@ -36,25 +36,28 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
         }
 
         val authRequest = if (originalRequest.method == "GET") originalRequest.newBuilder()
-                .header("User-Agent", "Tachiyomi")
-                .url(originalRequest.url.newBuilder()
-                        .addQueryParameter("access_token", currAuth.access_token).build())
-                .build() else originalRequest.newBuilder()
-                .post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
-                .header("User-Agent", "Tachiyomi")
-                .build()
+            .header("User-Agent", "Tachiyomi")
+            .url(
+                originalRequest.url.newBuilder()
+                    .addQueryParameter("access_token", currAuth.access_token).build()
+            )
+            .build() else originalRequest.newBuilder()
+            .post(addTocken(currAuth.access_token, originalRequest.body as FormBody))
+            .header("User-Agent", "Tachiyomi")
+            .build()
 
         return chain.proceed(authRequest)
     }
 
     fun newAuth(oauth: OAuth?) {
         this.oauth = if (oauth == null) null else OAuth(
-                oauth.access_token,
-                oauth.token_type,
-                System.currentTimeMillis() / 1000,
-                oauth.expires_in,
-                oauth.refresh_token,
-                this.oauth?.user_id)
+            oauth.access_token,
+            oauth.token_type,
+            System.currentTimeMillis() / 1000,
+            oauth.expires_in,
+            oauth.refresh_token,
+            this.oauth?.user_id
+        )
 
         bangumi.saveToken(oauth)
     }

+ 20 - 20
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt

@@ -78,17 +78,17 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
 
     override fun bind(track: Track): Observable<Track> {
         return api.findLibManga(track, getUserId())
-                .flatMap { remoteTrack ->
-                    if (remoteTrack != null) {
-                        track.copyPersonalFrom(remoteTrack)
-                        track.media_id = remoteTrack.media_id
-                        update(track)
-                    } else {
-                        track.score = DEFAULT_SCORE
-                        track.status = DEFAULT_STATUS
-                        add(track)
-                    }
+            .flatMap { remoteTrack ->
+                if (remoteTrack != null) {
+                    track.copyPersonalFrom(remoteTrack)
+                    track.media_id = remoteTrack.media_id
+                    update(track)
+                } else {
+                    track.score = DEFAULT_SCORE
+                    track.status = DEFAULT_STATUS
+                    add(track)
                 }
+            }
     }
 
     override fun search(query: String): Observable<List<TrackSearch>> {
@@ -97,20 +97,20 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
 
     override fun refresh(track: Track): Observable<Track> {
         return api.getLibManga(track)
-                .map { remoteTrack ->
-                    track.copyPersonalFrom(remoteTrack)
-                    track.total_chapters = remoteTrack.total_chapters
-                    track
-                }
+            .map { remoteTrack ->
+                track.copyPersonalFrom(remoteTrack)
+                track.total_chapters = remoteTrack.total_chapters
+                track
+            }
     }
 
     override fun login(username: String, password: String): Completable {
         return api.login(username, password)
-                .doOnNext { interceptor.newAuth(it) }
-                .flatMap { api.getCurrentUser() }
-                .doOnNext { userId -> saveCredentials(username, userId) }
-                .doOnError { logout() }
-                .toCompletable()
+            .doOnNext { interceptor.newAuth(it) }
+            .flatMap { api.getCurrentUser() }
+            .doOnNext { userId -> saveCredentials(username, userId) }
+            .doOnError { logout() }
+            .toCompletable()
     }
 
     override fun logout() {

+ 91 - 89
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt

@@ -33,59 +33,59 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
     private val authClient = client.newBuilder().addInterceptor(interceptor).build()
 
     private val rest = Retrofit.Builder()
-            .baseUrl(baseUrl)
-            .client(authClient)
-            .addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create()))
-            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
-            .build()
-            .create(Rest::class.java)
+        .baseUrl(baseUrl)
+        .client(authClient)
+        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create()))
+        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+        .build()
+        .create(Rest::class.java)
 
     private val searchRest = Retrofit.Builder()
-            .baseUrl(algoliaKeyUrl)
-            .client(authClient)
-            .addConverterFactory(GsonConverterFactory.create())
-            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
-            .build()
-            .create(SearchKeyRest::class.java)
+        .baseUrl(algoliaKeyUrl)
+        .client(authClient)
+        .addConverterFactory(GsonConverterFactory.create())
+        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+        .build()
+        .create(SearchKeyRest::class.java)
 
     private val algoliaRest = Retrofit.Builder()
-            .baseUrl(algoliaUrl)
-            .client(client)
-            .addConverterFactory(GsonConverterFactory.create())
-            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
-            .build()
-            .create(AgoliaSearchRest::class.java)
+        .baseUrl(algoliaUrl)
+        .client(client)
+        .addConverterFactory(GsonConverterFactory.create())
+        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+        .build()
+        .create(AgoliaSearchRest::class.java)
 
     fun addLibManga(track: Track, userId: String): Observable<Track> {
         return Observable.defer {
             // @formatter:off
             val data = jsonObject(
-                    "type" to "libraryEntries",
-                    "attributes" to jsonObject(
-                            "status" to track.toKitsuStatus(),
-                            "progress" to track.last_chapter_read
+                "type" to "libraryEntries",
+                "attributes" to jsonObject(
+                    "status" to track.toKitsuStatus(),
+                    "progress" to track.last_chapter_read
+                ),
+                "relationships" to jsonObject(
+                    "user" to jsonObject(
+                        "data" to jsonObject(
+                            "id" to userId,
+                            "type" to "users"
+                        )
                     ),
-                    "relationships" to jsonObject(
-                            "user" to jsonObject(
-                                    "data" to jsonObject(
-                                            "id" to userId,
-                                            "type" to "users"
-                                    )
-                            ),
-                            "media" to jsonObject(
-                                    "data" to jsonObject(
-                                            "id" to track.media_id,
-                                            "type" to "manga"
-                                    )
-                            )
+                    "media" to jsonObject(
+                        "data" to jsonObject(
+                            "id" to track.media_id,
+                            "type" to "manga"
+                        )
                     )
+                )
             )
 
             rest.addLibManga(jsonObject("data" to data))
-                    .map { json ->
-                        track.media_id = json["data"]["id"].int
-                        track
-                    }
+                .map { json ->
+                    track.media_id = json["data"]["id"].int
+                    track
+                }
         }
     }
 
@@ -93,77 +93,77 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
         return Observable.defer {
             // @formatter:off
             val data = jsonObject(
-                    "type" to "libraryEntries",
-                    "id" to track.media_id,
-                    "attributes" to jsonObject(
-                            "status" to track.toKitsuStatus(),
-                            "progress" to track.last_chapter_read,
-                            "ratingTwenty" to track.toKitsuScore()
-                    )
+                "type" to "libraryEntries",
+                "id" to track.media_id,
+                "attributes" to jsonObject(
+                    "status" to track.toKitsuStatus(),
+                    "progress" to track.last_chapter_read,
+                    "ratingTwenty" to track.toKitsuScore()
+                )
             )
             // @formatter:on
 
             rest.updateLibManga(track.media_id, jsonObject("data" to data))
-                    .map { track }
+                .map { track }
         }
     }
 
     fun search(query: String): Observable<List<TrackSearch>> {
         return searchRest
-                .getKey().map { json ->
-                    json["media"].asJsonObject["key"].string
-                }.flatMap { key ->
-                    algoliaSearch(key, query)
-                }
+            .getKey().map { json ->
+                json["media"].asJsonObject["key"].string
+            }.flatMap { key ->
+                algoliaSearch(key, query)
+            }
     }
 
     private fun algoliaSearch(key: String, query: String): Observable<List<TrackSearch>> {
         val jsonObject = jsonObject("params" to "query=$query$algoliaFilter")
         return algoliaRest
-                .getSearchQuery(algoliaAppId, key, jsonObject)
-                .map { json ->
-                    val data = json["hits"].array
-                    data.map { KitsuSearchManga(it.obj) }
-                            .filter { it.subType != "novel" }
-                            .map { it.toTrack() }
-                }
+            .getSearchQuery(algoliaAppId, key, jsonObject)
+            .map { json ->
+                val data = json["hits"].array
+                data.map { KitsuSearchManga(it.obj) }
+                    .filter { it.subType != "novel" }
+                    .map { it.toTrack() }
+            }
     }
 
     fun findLibManga(track: Track, userId: String): Observable<Track?> {
         return rest.findLibManga(track.media_id, userId)
-                .map { json ->
-                    val data = json["data"].array
-                    if (data.size() > 0) {
-                        val manga = json["included"].array[0].obj
-                        KitsuLibManga(data[0].obj, manga).toTrack()
-                    } else {
-                        null
-                    }
+            .map { json ->
+                val data = json["data"].array
+                if (data.size() > 0) {
+                    val manga = json["included"].array[0].obj
+                    KitsuLibManga(data[0].obj, manga).toTrack()
+                } else {
+                    null
                 }
+            }
     }
 
     fun getLibManga(track: Track): Observable<Track> {
         return rest.getLibManga(track.media_id)
-                .map { json ->
-                    val data = json["data"].array
-                    if (data.size() > 0) {
-                        val manga = json["included"].array[0].obj
-                        KitsuLibManga(data[0].obj, manga).toTrack()
-                    } else {
-                        throw Exception("Could not find manga")
-                    }
+            .map { json ->
+                val data = json["data"].array
+                if (data.size() > 0) {
+                    val manga = json["included"].array[0].obj
+                    KitsuLibManga(data[0].obj, manga).toTrack()
+                } else {
+                    throw Exception("Could not find manga")
                 }
+            }
     }
 
     fun login(username: String, password: String): Observable<OAuth> {
         return Retrofit.Builder()
-                .baseUrl(loginUrl)
-                .client(client)
-                .addConverterFactory(GsonConverterFactory.create())
-                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
-                .build()
-                .create(LoginRest::class.java)
-                .requestAccessToken(username, password)
+            .baseUrl(loginUrl)
+            .client(client)
+            .addConverterFactory(GsonConverterFactory.create())
+            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+            .build()
+            .create(LoginRest::class.java)
+            .requestAccessToken(username, password)
     }
 
     fun getCurrentUser(): Observable<String> {
@@ -242,12 +242,14 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
             return baseMangaUrl + remoteId
         }
 
-        fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",
-                body = FormBody.Builder()
-                        .add("grant_type", "refresh_token")
-                        .add("client_id", clientId)
-                        .add("client_secret", clientSecret)
-                        .add("refresh_token", token)
-                        .build())
+        fun refreshTokenRequest(token: String) = POST(
+            "${loginUrl}oauth/token",
+            body = FormBody.Builder()
+                .add("grant_type", "refresh_token")
+                .add("client_id", clientId)
+                .add("client_secret", clientSecret)
+                .add("refresh_token", token)
+                .build()
+        )
     }
 }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuInterceptor.kt

@@ -30,10 +30,10 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
 
         // Add the authorization header to the original request.
         val authRequest = originalRequest.newBuilder()
-                .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
-                .header("Accept", "application/vnd.api+json")
-                .header("Content-Type", "application/vnd.api+json")
-                .build()
+            .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
+            .header("Accept", "application/vnd.api+json")
+            .header("Content-Type", "application/vnd.api+json")
+            .build()
 
         return chain.proceed(authRequest)
     }

+ 23 - 22
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeList.kt

@@ -74,17 +74,17 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
 
     override fun bind(track: Track): Observable<Track> {
         return api.findLibManga(track)
-                .flatMap { remoteTrack ->
-                    if (remoteTrack != null) {
-                        track.copyPersonalFrom(remoteTrack)
-                        update(track)
-                    } else {
-                        // Set default fields if it's not found in the list
-                        track.score = DEFAULT_SCORE.toFloat()
-                        track.status = DEFAULT_STATUS
-                        add(track)
-                    }
+            .flatMap { remoteTrack ->
+                if (remoteTrack != null) {
+                    track.copyPersonalFrom(remoteTrack)
+                    update(track)
+                } else {
+                    // Set default fields if it's not found in the list
+                    track.score = DEFAULT_SCORE.toFloat()
+                    track.status = DEFAULT_STATUS
+                    add(track)
                 }
+            }
     }
 
     override fun search(query: String): Observable<List<TrackSearch>> {
@@ -93,21 +93,21 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
 
     override fun refresh(track: Track): Observable<Track> {
         return api.getLibManga(track)
-                .map { remoteTrack ->
-                    track.copyPersonalFrom(remoteTrack)
-                    track.total_chapters = remoteTrack.total_chapters
-                    track
-                }
+            .map { remoteTrack ->
+                track.copyPersonalFrom(remoteTrack)
+                track.total_chapters = remoteTrack.total_chapters
+                track
+            }
     }
 
     override fun login(username: String, password: String): Completable {
         logout()
 
         return Observable.fromCallable { api.login(username, password) }
-                .doOnNext { csrf -> saveCSRF(csrf) }
-                .doOnNext { saveCredentials(username, password) }
-                .doOnError { logout() }
-                .toCompletable()
+            .doOnNext { csrf -> saveCSRF(csrf) }
+            .doOnNext { saveCredentials(username, password) }
+            .doOnError { logout() }
+            .toCompletable()
     }
 
     fun refreshLogin() {
@@ -141,8 +141,8 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
 
     val isAuthorized: Boolean
         get() = super.isLogged &&
-                getCSRF().isNotEmpty() &&
-                checkCookies()
+            getCSRF().isNotEmpty() &&
+            checkCookies()
 
     fun getCSRF(): String = preferences.trackToken(this).get()
 
@@ -152,8 +152,9 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
         var ckCount = 0
         val url = BASE_URL.toHttpUrlOrNull()!!
         for (ck in networkService.cookieManager.get(url)) {
-            if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE)
+            if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE) {
                 ckCount++
+            }
         }
 
         return ckCount == 2

+ 177 - 172
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListApi.kt

@@ -39,43 +39,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         return if (query.startsWith(PREFIX_MY)) {
             val realQuery = query.removePrefix(PREFIX_MY)
             getList()
-                    .flatMap { Observable.from(it) }
-                    .filter { it.title.contains(realQuery, true) }
-                    .toList()
+                .flatMap { Observable.from(it) }
+                .filter { it.title.contains(realQuery, true) }
+                .toList()
         } else {
             client.newCall(GET(searchUrl(query)))
-                    .asObservable()
-                    .flatMap { response ->
-                        Observable.from(Jsoup.parse(response.consumeBody())
-                                .select("div.js-categories-seasonal.js-block-list.list")
-                                .select("table").select("tbody")
-                                .select("tr").drop(1))
-                    }
-                    .filter { row ->
-                        row.select(TD)[2].text() != "Novel"
-                    }
-                    .map { row ->
-                        TrackSearch.create(TrackManager.MYANIMELIST).apply {
-                            title = row.searchTitle()
-                            media_id = row.searchMediaId()
-                            total_chapters = row.searchTotalChapters()
-                            summary = row.searchSummary()
-                            cover_url = row.searchCoverUrl()
-                            tracking_url = mangaUrl(media_id)
-                            publishing_status = row.searchPublishingStatus()
-                            publishing_type = row.searchPublishingType()
-                            start_date = row.searchStartDate()
-                        }
+                .asObservable()
+                .flatMap { response ->
+                    Observable.from(
+                        Jsoup.parse(response.consumeBody())
+                            .select("div.js-categories-seasonal.js-block-list.list")
+                            .select("table").select("tbody")
+                            .select("tr").drop(1)
+                    )
+                }
+                .filter { row ->
+                    row.select(TD)[2].text() != "Novel"
+                }
+                .map { row ->
+                    TrackSearch.create(TrackManager.MYANIMELIST).apply {
+                        title = row.searchTitle()
+                        media_id = row.searchMediaId()
+                        total_chapters = row.searchTotalChapters()
+                        summary = row.searchSummary()
+                        cover_url = row.searchCoverUrl()
+                        tracking_url = mangaUrl(media_id)
+                        publishing_status = row.searchPublishingStatus()
+                        publishing_type = row.searchPublishingType()
+                        start_date = row.searchStartDate()
                     }
-                    .toList()
+                }
+                .toList()
         }
     }
 
     fun addLibManga(track: Track): Observable<Track> {
         return Observable.defer {
             authClient.newCall(POST(url = addUrl(), body = mangaPostPayload(track)))
-                    .asObservableSuccess()
-                    .map { track }
+                .asObservableSuccess()
+                .map { track }
         }
     }
 
@@ -95,40 +97,40 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
 
             // Update remote
             authClient.newCall(POST(url = editPageUrl(track.media_id), body = mangaEditPostBody(editData)))
-                    .asObservableSuccess()
-                    .map {
-                        track
-                    }
+                .asObservableSuccess()
+                .map {
+                    track
+                }
         }
     }
 
     fun findLibManga(track: Track): Observable<Track?> {
         return authClient.newCall(GET(url = editPageUrl(track.media_id)))
-                .asObservable()
-                .map { response ->
-                    var libTrack: Track? = null
-                    response.use {
-                        if (it.priorResponse?.isRedirect != true) {
-                            val trackForm = Jsoup.parse(it.consumeBody())
-
-                            libTrack = Track.create(TrackManager.MYANIMELIST).apply {
-                                last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt()
-                                total_chapters = trackForm.select("#totalChap").text().toInt()
-                                status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt()
-                                score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull()
-                                        ?: 0f
-                                started_reading_date = trackForm.searchDatePicker("#add_manga_start_date")
-                                finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date")
-                            }
+            .asObservable()
+            .map { response ->
+                var libTrack: Track? = null
+                response.use {
+                    if (it.priorResponse?.isRedirect != true) {
+                        val trackForm = Jsoup.parse(it.consumeBody())
+
+                        libTrack = Track.create(TrackManager.MYANIMELIST).apply {
+                            last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt()
+                            total_chapters = trackForm.select("#totalChap").text().toInt()
+                            status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt()
+                            score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull()
+                                ?: 0f
+                            started_reading_date = trackForm.searchDatePicker("#add_manga_start_date")
+                            finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date")
                         }
                     }
-                    libTrack
                 }
+                libTrack
+            }
     }
 
     fun getLibManga(track: Track): Observable<Track> {
         return findLibManga(track)
-                .map { it ?: throw Exception("Could not find manga") }
+            .map { it ?: throw Exception("Could not find manga") }
     }
 
     fun login(username: String, password: String): String {
@@ -143,8 +145,8 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         val response = client.newCall(GET(loginUrl())).execute()
 
         return Jsoup.parse(response.consumeBody())
-                .select("meta[name=csrf_token]")
-                .attr("content")
+            .select("meta[name=csrf_token]")
+            .attr("content")
     }
 
     private fun login(username: String, password: String, csrf: String) {
@@ -157,45 +159,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
 
     private fun getList(): Observable<List<TrackSearch>> {
         return getListUrl()
-                .flatMap { url ->
-                    getListXml(url)
-                }
-                .flatMap { doc ->
-                    Observable.from(doc.select("manga"))
-                }
-                .map {
-                    TrackSearch.create(TrackManager.MYANIMELIST).apply {
-                        title = it.selectText("manga_title")!!
-                        media_id = it.selectInt("manga_mangadb_id")
-                        last_chapter_read = it.selectInt("my_read_chapters")
-                        status = getStatus(it.selectText("my_status")!!)
-                        score = it.selectInt("my_score").toFloat()
-                        total_chapters = it.selectInt("manga_chapters")
-                        tracking_url = mangaUrl(media_id)
-                        started_reading_date = it.searchDateXml("my_start_date")
-                        finished_reading_date = it.searchDateXml("my_finish_date")
-                    }
+            .flatMap { url ->
+                getListXml(url)
+            }
+            .flatMap { doc ->
+                Observable.from(doc.select("manga"))
+            }
+            .map {
+                TrackSearch.create(TrackManager.MYANIMELIST).apply {
+                    title = it.selectText("manga_title")!!
+                    media_id = it.selectInt("manga_mangadb_id")
+                    last_chapter_read = it.selectInt("my_read_chapters")
+                    status = getStatus(it.selectText("my_status")!!)
+                    score = it.selectInt("my_score").toFloat()
+                    total_chapters = it.selectInt("manga_chapters")
+                    tracking_url = mangaUrl(media_id)
+                    started_reading_date = it.searchDateXml("my_start_date")
+                    finished_reading_date = it.searchDateXml("my_finish_date")
                 }
-                .toList()
+            }
+            .toList()
     }
 
     private fun getListUrl(): Observable<String> {
         return authClient.newCall(POST(url = exportListUrl(), body = exportPostBody()))
-                .asObservable()
-                .map { response ->
-                    baseUrl + Jsoup.parse(response.consumeBody())
-                            .select("div.goodresult")
-                            .select("a")
-                            .attr("href")
-                }
+            .asObservable()
+            .map { response ->
+                baseUrl + Jsoup.parse(response.consumeBody())
+                    .select("div.goodresult")
+                    .select("a")
+                    .attr("href")
+            }
     }
 
     private fun getListXml(url: String): Observable<Document> {
         return authClient.newCall(GET(url))
-                .asObservable()
-                .map { response ->
-                    Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser())
-                }
+            .asObservable()
+            .map { response ->
+                Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser())
+            }
     }
 
     private fun Response.consumeBody(): String? {
@@ -222,28 +224,28 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         val tables = page.select("form#main-form table")
 
         return MyAnimeListEditData(
-                entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0
-                manga_id = tables[0].select("#manga_id").`val`(),
-                status = tables[0].select("#add_manga_status > option[selected]").`val`(),
-                num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(),
-                last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty
-                num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(),
-                score = tables[0].select("#add_manga_score > option[selected]").`val`(),
-                start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(),
-                start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(),
-                start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(),
-                finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(),
-                finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(),
-                finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(),
-                tags = tables[1].select("#add_manga_tags").`val`(),
-                priority = tables[1].select("#add_manga_priority > option[selected]").`val`(),
-                storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(),
-                num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(),
-                num_read_times = tables[1].select("#add_manga_num_read_times").`val`(),
-                reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(),
-                comments = tables[1].select("#add_manga_comments").`val`(),
-                is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(),
-                sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`()
+            entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0
+            manga_id = tables[0].select("#manga_id").`val`(),
+            status = tables[0].select("#add_manga_status > option[selected]").`val`(),
+            num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(),
+            last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty
+            num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(),
+            score = tables[0].select("#add_manga_score > option[selected]").`val`(),
+            start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(),
+            start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(),
+            start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(),
+            finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(),
+            finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(),
+            finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(),
+            tags = tables[1].select("#add_manga_tags").`val`(),
+            priority = tables[1].select("#add_manga_priority > option[selected]").`val`(),
+            storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(),
+            num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(),
+            num_read_times = tables[1].select("#add_manga_num_read_times").`val`(),
+            reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(),
+            comments = tables[1].select("#add_manga_comments").`val`(),
+            is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(),
+            sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`()
         )
     }
 
@@ -259,98 +261,99 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId
 
         private fun loginUrl() = Uri.parse(baseUrl).buildUpon()
-                .appendPath("login.php")
-                .toString()
+            .appendPath("login.php")
+            .toString()
 
         private fun searchUrl(query: String): String {
             val col = "c[]"
             return Uri.parse(baseUrl).buildUpon()
-                    .appendPath("manga.php")
-                    .appendQueryParameter("q", query)
-                    .appendQueryParameter(col, "a")
-                    .appendQueryParameter(col, "b")
-                    .appendQueryParameter(col, "c")
-                    .appendQueryParameter(col, "d")
-                    .appendQueryParameter(col, "e")
-                    .appendQueryParameter(col, "g")
-                    .toString()
+                .appendPath("manga.php")
+                .appendQueryParameter("q", query)
+                .appendQueryParameter(col, "a")
+                .appendQueryParameter(col, "b")
+                .appendQueryParameter(col, "c")
+                .appendQueryParameter(col, "d")
+                .appendQueryParameter(col, "e")
+                .appendQueryParameter(col, "g")
+                .toString()
         }
 
         private fun exportListUrl() = Uri.parse(baseUrl).buildUpon()
-                .appendPath("panel.php")
-                .appendQueryParameter("go", "export")
-                .toString()
+            .appendPath("panel.php")
+            .appendQueryParameter("go", "export")
+            .toString()
 
         private fun editPageUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon()
-                .appendPath(mediaId.toString())
-                .appendPath("edit")
-                .toString()
+            .appendPath(mediaId.toString())
+            .appendPath("edit")
+            .toString()
 
         private fun addUrl() = Uri.parse(baseModifyListUrl).buildUpon()
-                .appendPath("add.json")
-                .toString()
+            .appendPath("add.json")
+            .toString()
 
         private fun loginPostBody(username: String, password: String, csrf: String): RequestBody {
             return FormBody.Builder()
-                    .add("user_name", username)
-                    .add("password", password)
-                    .add("cookie", "1")
-                    .add("sublogin", "Login")
-                    .add("submit", "1")
-                    .add(CSRF, csrf)
-                    .build()
+                .add("user_name", username)
+                .add("password", password)
+                .add("cookie", "1")
+                .add("sublogin", "Login")
+                .add("submit", "1")
+                .add(CSRF, csrf)
+                .build()
         }
 
         private fun exportPostBody(): RequestBody {
             return FormBody.Builder()
-                    .add("type", "2")
-                    .add("subexport", "Export My List")
-                    .build()
+                .add("type", "2")
+                .add("subexport", "Export My List")
+                .build()
         }
 
         private fun mangaPostPayload(track: Track): RequestBody {
             val body = JSONObject()
-                    .put("manga_id", track.media_id)
-                    .put("status", track.status)
-                    .put("score", track.score)
-                    .put("num_read_chapters", track.last_chapter_read)
+                .put("manga_id", track.media_id)
+                .put("status", track.status)
+                .put("score", track.score)
+                .put("num_read_chapters", track.last_chapter_read)
 
             return body.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
         }
 
         private fun mangaEditPostBody(track: MyAnimeListEditData): RequestBody {
             return FormBody.Builder()
-                    .add("entry_id", track.entry_id)
-                    .add("manga_id", track.manga_id)
-                    .add("add_manga[status]", track.status)
-                    .add("add_manga[num_read_volumes]", track.num_read_volumes)
-                    .add("last_completed_vol", track.last_completed_vol)
-                    .add("add_manga[num_read_chapters]", track.num_read_chapters)
-                    .add("add_manga[score]", track.score)
-                    .add("add_manga[start_date][month]", track.start_date_month)
-                    .add("add_manga[start_date][day]", track.start_date_day)
-                    .add("add_manga[start_date][year]", track.start_date_year)
-                    .add("add_manga[finish_date][month]", track.finish_date_month)
-                    .add("add_manga[finish_date][day]", track.finish_date_day)
-                    .add("add_manga[finish_date][year]", track.finish_date_year)
-                    .add("add_manga[tags]", track.tags)
-                    .add("add_manga[priority]", track.priority)
-                    .add("add_manga[storage_type]", track.storage_type)
-                    .add("add_manga[num_retail_volumes]", track.num_retail_volumes)
-                    .add("add_manga[num_read_times]", track.num_read_chapters)
-                    .add("add_manga[reread_value]", track.reread_value)
-                    .add("add_manga[comments]", track.comments)
-                    .add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss)
-                    .add("add_manga[sns_post_type]", track.sns_post_type)
-                    .add("submitIt", track.submitIt)
-                    .build()
+                .add("entry_id", track.entry_id)
+                .add("manga_id", track.manga_id)
+                .add("add_manga[status]", track.status)
+                .add("add_manga[num_read_volumes]", track.num_read_volumes)
+                .add("last_completed_vol", track.last_completed_vol)
+                .add("add_manga[num_read_chapters]", track.num_read_chapters)
+                .add("add_manga[score]", track.score)
+                .add("add_manga[start_date][month]", track.start_date_month)
+                .add("add_manga[start_date][day]", track.start_date_day)
+                .add("add_manga[start_date][year]", track.start_date_year)
+                .add("add_manga[finish_date][month]", track.finish_date_month)
+                .add("add_manga[finish_date][day]", track.finish_date_day)
+                .add("add_manga[finish_date][year]", track.finish_date_year)
+                .add("add_manga[tags]", track.tags)
+                .add("add_manga[priority]", track.priority)
+                .add("add_manga[storage_type]", track.storage_type)
+                .add("add_manga[num_retail_volumes]", track.num_retail_volumes)
+                .add("add_manga[num_read_times]", track.num_read_chapters)
+                .add("add_manga[reread_value]", track.reread_value)
+                .add("add_manga[comments]", track.comments)
+                .add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss)
+                .add("add_manga[sns_post_type]", track.sns_post_type)
+                .add("submitIt", track.submitIt)
+                .build()
         }
 
         private fun Element.searchDateXml(field: String): Long {
             val text = selectText(field, "0000-00-00")!!
             // MAL sets the data to 0000-00-00 when date is invalid or missing
-            if (text == "0000-00-00")
+            if (text == "0000-00-00") {
                 return 0L
+            }
 
             return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(text)?.time ?: 0L
         }
@@ -359,8 +362,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
             val month = select(id + "_month > option[selected]").`val`().toIntOrNull()
             val day = select(id + "_day > option[selected]").`val`().toIntOrNull()
             val year = select(id + "_year > option[selected]").`val`().toIntOrNull()
-            if (year == null || month == null || day == null)
+            if (year == null || month == null || day == null) {
                 return 0L
+            }
 
             return GregorianCalendar(year, month - 1, day).timeInMillis
         }
@@ -370,18 +374,18 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         private fun Element.searchTotalChapters() = if (select(TD)[4].text() == "-") 0 else select(TD)[4].text().toInt()
 
         private fun Element.searchCoverUrl() = select("img")
-                .attr("data-src")
-                .split("\\?")[0]
-                .replace("/r/50x70/", "/")
+            .attr("data-src")
+            .split("\\?")[0]
+            .replace("/r/50x70/", "/")
 
         private fun Element.searchMediaId() = select("div.picSurround")
-                .select("a").attr("id")
-                .replace("sarea", "")
-                .toInt()
+            .select("a").attr("id")
+            .replace("sarea", "")
+            .toInt()
 
         private fun Element.searchSummary() = select("div.pt4")
-                .first()
-                .ownText()!!
+            .first()
+            .ownText()!!
 
         private fun Element.searchPublishingStatus() = if (select(TD).last().text() == "-") "Publishing" else "Finished"
 
@@ -472,8 +476,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
         fun copyPersonalFrom(track: Track) {
             num_read_chapters = track.last_chapter_read.toString()
             val numScore = track.score.toInt()
-            if (numScore in 1..9)
+            if (numScore in 1..9) {
                 score = numScore.toString()
+            }
             status = track.status.toString()
             if (track.started_reading_date == 0L) {
                 start_date_month = ""

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyAnimeListInterceptor.kt

@@ -53,7 +53,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
     private fun updateJsonBody(requestBody: RequestBody): RequestBody {
         val jsonString = bodyToString(requestBody)
         val newBody = JSONObject(jsonString)
-                .put(MyAnimeListApi.CSRF, myanimelist.getCSRF())
+            .put(MyAnimeListApi.CSRF, myanimelist.getCSRF())
 
         return newBody.toString().toRequestBody(requestBody.contentType())
     }

+ 17 - 17
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/Shikimori.kt

@@ -51,18 +51,18 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
 
     override fun bind(track: Track): Observable<Track> {
         return api.findLibManga(track, getUsername())
-                .flatMap { remoteTrack ->
-                    if (remoteTrack != null) {
-                        track.copyPersonalFrom(remoteTrack)
-                        track.library_id = remoteTrack.library_id
-                        update(track)
-                    } else {
-                        // Set default fields if it's not found in the list
-                        track.score = DEFAULT_SCORE.toFloat()
-                        track.status = DEFAULT_STATUS
-                        add(track)
-                    }
+            .flatMap { remoteTrack ->
+                if (remoteTrack != null) {
+                    track.copyPersonalFrom(remoteTrack)
+                    track.library_id = remoteTrack.library_id
+                    update(track)
+                } else {
+                    // Set default fields if it's not found in the list
+                    track.score = DEFAULT_SCORE.toFloat()
+                    track.status = DEFAULT_STATUS
+                    add(track)
                 }
+            }
     }
 
     override fun search(query: String): Observable<List<TrackSearch>> {
@@ -71,13 +71,13 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
 
     override fun refresh(track: Track): Observable<Track> {
         return api.findLibManga(track, getUsername())
-                .map { remoteTrack ->
-                    if (remoteTrack != null) {
-                        track.copyPersonalFrom(remoteTrack)
-                        track.total_chapters = remoteTrack.total_chapters
-                    }
-                    track
+            .map { remoteTrack ->
+                if (remoteTrack != null) {
+                    track.copyPersonalFrom(remoteTrack)
+                    track.total_chapters = remoteTrack.total_chapters
                 }
+                track
+            }
     }
 
     override fun getLogo() = R.drawable.ic_tracker_shikimori

+ 88 - 85
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriApi.kt

@@ -30,49 +30,49 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
 
     fun addLibManga(track: Track, user_id: String): Observable<Track> {
         val payload = jsonObject(
-                "user_rate" to jsonObject(
-                        "user_id" to user_id,
-                        "target_id" to track.media_id,
-                        "target_type" to "Manga",
-                        "chapters" to track.last_chapter_read,
-                        "score" to track.score.toInt(),
-                        "status" to track.toShikimoriStatus()
-                )
+            "user_rate" to jsonObject(
+                "user_id" to user_id,
+                "target_id" to track.media_id,
+                "target_type" to "Manga",
+                "chapters" to track.last_chapter_read,
+                "score" to track.score.toInt(),
+                "status" to track.toShikimoriStatus()
+            )
         )
         val body = payload.toString().toRequestBody(jsonime)
         val request = Request.Builder()
-                .url("$apiUrl/v2/user_rates")
-                .post(body)
-                .build()
+            .url("$apiUrl/v2/user_rates")
+            .post(body)
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map {
-                    track
-                }
+            .asObservableSuccess()
+            .map {
+                track
+            }
     }
 
     fun updateLibManga(track: Track, user_id: String): Observable<Track> = addLibManga(track, user_id)
 
     fun search(search: String): Observable<List<TrackSearch>> {
         val url = Uri.parse("$apiUrl/mangas").buildUpon()
-                .appendQueryParameter("order", "popularity")
-                .appendQueryParameter("search", search)
-                .appendQueryParameter("limit", "20")
-                .build()
+            .appendQueryParameter("order", "popularity")
+            .appendQueryParameter("search", search)
+            .appendQueryParameter("limit", "20")
+            .build()
         val request = Request.Builder()
-                .url(url.toString())
-                .get()
-                .build()
+            .url(url.toString())
+            .get()
+            .build()
         return authClient.newCall(request)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    if (responseBody.isEmpty()) {
-                        throw Exception("Null Response")
-                    }
-                    val response = JsonParser.parseString(responseBody).array
-                    response.map { jsonToSearch(it.obj) }
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                if (responseBody.isEmpty()) {
+                    throw Exception("Null Response")
                 }
+                val response = JsonParser.parseString(responseBody).array
+                response.map { jsonToSearch(it.obj) }
+            }
     }
 
     private fun jsonToSearch(obj: JsonObject): TrackSearch {
@@ -103,45 +103,45 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
 
     fun findLibManga(track: Track, user_id: String): Observable<Track?> {
         val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon()
-                .appendQueryParameter("user_id", user_id)
-                .appendQueryParameter("target_id", track.media_id.toString())
-                .appendQueryParameter("target_type", "Manga")
-                .build()
+            .appendQueryParameter("user_id", user_id)
+            .appendQueryParameter("target_id", track.media_id.toString())
+            .appendQueryParameter("target_type", "Manga")
+            .build()
         val request = Request.Builder()
-                .url(url.toString())
-                .get()
-                .build()
+            .url(url.toString())
+            .get()
+            .build()
 
         val urlMangas = Uri.parse("$apiUrl/mangas").buildUpon()
-                .appendPath(track.media_id.toString())
-                .build()
+            .appendPath(track.media_id.toString())
+            .build()
         val requestMangas = Request.Builder()
-                .url(urlMangas.toString())
-                .get()
-                .build()
+            .url(urlMangas.toString())
+            .get()
+            .build()
         return authClient.newCall(requestMangas)
-                .asObservableSuccess()
-                .map { netResponse ->
-                    val responseBody = netResponse.body?.string().orEmpty()
-                    JsonParser.parseString(responseBody).obj
-                }.flatMap { mangas ->
-                    authClient.newCall(request)
-                            .asObservableSuccess()
-                            .map { netResponse ->
-                                val responseBody = netResponse.body?.string().orEmpty()
-                                if (responseBody.isEmpty()) {
-                                    throw Exception("Null Response")
-                                }
-                                val response = JsonParser.parseString(responseBody).array
-                                if (response.size() > 1) {
-                                    throw Exception("Too much mangas in response")
-                                }
-                                val entry = response.map {
-                                    jsonToTrack(it.obj, mangas)
-                                }
-                                entry.firstOrNull()
-                            }
-                }
+            .asObservableSuccess()
+            .map { netResponse ->
+                val responseBody = netResponse.body?.string().orEmpty()
+                JsonParser.parseString(responseBody).obj
+            }.flatMap { mangas ->
+                authClient.newCall(request)
+                    .asObservableSuccess()
+                    .map { netResponse ->
+                        val responseBody = netResponse.body?.string().orEmpty()
+                        if (responseBody.isEmpty()) {
+                            throw Exception("Null Response")
+                        }
+                        val response = JsonParser.parseString(responseBody).array
+                        if (response.size() > 1) {
+                            throw Exception("Too much mangas in response")
+                        }
+                        val entry = response.map {
+                            jsonToTrack(it.obj, mangas)
+                        }
+                        entry.firstOrNull()
+                    }
+            }
     }
 
     fun getCurrentUser(): Int {
@@ -159,14 +159,15 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
         }
     }
 
-    private fun accessTokenRequest(code: String) = POST(oauthUrl,
-            body = FormBody.Builder()
-                    .add("grant_type", "authorization_code")
-                    .add("client_id", clientId)
-                    .add("client_secret", clientSecret)
-                    .add("code", code)
-                    .add("redirect_uri", redirectUrl)
-                    .build()
+    private fun accessTokenRequest(code: String) = POST(
+        oauthUrl,
+        body = FormBody.Builder()
+            .add("grant_type", "authorization_code")
+            .add("client_id", clientId)
+            .add("client_secret", clientSecret)
+            .add("code", code)
+            .add("redirect_uri", redirectUrl)
+            .build()
     )
 
     companion object {
@@ -186,18 +187,20 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
         }
 
         fun authUrl() =
-                Uri.parse(loginUrl).buildUpon()
-                        .appendQueryParameter("client_id", clientId)
-                        .appendQueryParameter("redirect_uri", redirectUrl)
-                        .appendQueryParameter("response_type", "code")
-                        .build()
-
-        fun refreshTokenRequest(token: String) = POST(oauthUrl,
-                body = FormBody.Builder()
-                        .add("grant_type", "refresh_token")
-                        .add("client_id", clientId)
-                        .add("client_secret", clientSecret)
-                        .add("refresh_token", token)
-                        .build())
+            Uri.parse(loginUrl).buildUpon()
+                .appendQueryParameter("client_id", clientId)
+                .appendQueryParameter("redirect_uri", redirectUrl)
+                .appendQueryParameter("response_type", "code")
+                .build()
+
+        fun refreshTokenRequest(token: String) = POST(
+            oauthUrl,
+            body = FormBody.Builder()
+                .add("grant_type", "refresh_token")
+                .add("client_id", clientId)
+                .add("client_secret", clientSecret)
+                .add("refresh_token", token)
+                .build()
+        )
     }
 }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/track/shikimori/ShikimoriInterceptor.kt

@@ -29,9 +29,9 @@ class ShikimoriInterceptor(val shikimori: Shikimori, val gson: Gson) : Intercept
         }
         // Add the authorization header to the original request.
         val authRequest = originalRequest.newBuilder()
-                .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
-                .header("User-Agent", "Tachiyomi")
-                .build()
+            .addHeader("Authorization", "Bearer ${oauth!!.access_token}")
+            .header("User-Agent", "Tachiyomi")
+            .build()
 
         return chain.proceed(authRequest)
     }

+ 14 - 11
app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterJob.kt

@@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit
 import kotlinx.coroutines.runBlocking
 
 class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
-        Worker(context, workerParams) {
+    Worker(context, workerParams) {
 
     override fun doWork(): Result {
         return runBlocking {
@@ -37,9 +37,11 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
                         setContentText(context.getString(R.string.update_check_notification_update_available))
                         setSmallIcon(android.R.drawable.stat_sys_download_done)
                         // Download action
-                        addAction(android.R.drawable.stat_sys_download_done,
-                                context.getString(R.string.action_download),
-                                PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT))
+                        addAction(
+                            android.R.drawable.stat_sys_download_done,
+                            context.getString(R.string.action_download),
+                            PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
+                        )
                     }
                 }
                 Result.success()
@@ -59,15 +61,16 @@ class UpdaterJob(private val context: Context, workerParams: WorkerParameters) :
 
         fun setupTask(context: Context) {
             val constraints = Constraints.Builder()
-                    .setRequiredNetworkType(NetworkType.CONNECTED)
-                    .build()
+                .setRequiredNetworkType(NetworkType.CONNECTED)
+                .build()
 
             val request = PeriodicWorkRequestBuilder<UpdaterJob>(
-                    3, TimeUnit.DAYS,
-                    3, TimeUnit.HOURS)
-                    .addTag(TAG)
-                    .setConstraints(constraints)
-                    .build()
+                3, TimeUnit.DAYS,
+                3, TimeUnit.HOURS
+            )
+                .addTag(TAG)
+                .setConstraints(constraints)
+                .build()
 
             WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request)
         }

+ 20 - 12
app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdaterNotifier.kt

@@ -69,13 +69,17 @@ internal class UpdaterNotifier(private val context: Context) {
             setProgress(0, 0, false)
             // Install action
             setContentIntent(NotificationHandler.installApkPendingActivity(context, uri))
-            addAction(R.drawable.ic_system_update_alt_white_24dp,
-                    context.getString(R.string.action_install),
-                    NotificationHandler.installApkPendingActivity(context, uri))
+            addAction(
+                R.drawable.ic_system_update_alt_white_24dp,
+                context.getString(R.string.action_install),
+                NotificationHandler.installApkPendingActivity(context, uri)
+            )
             // Cancel action
-            addAction(R.drawable.ic_close_24dp,
-                    context.getString(R.string.action_cancel),
-                    NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
+            addAction(
+                R.drawable.ic_close_24dp,
+                context.getString(R.string.action_cancel),
+                NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
+            )
         }
         notificationBuilder.show()
     }
@@ -92,13 +96,17 @@ internal class UpdaterNotifier(private val context: Context) {
             setOnlyAlertOnce(false)
             setProgress(0, 0, false)
             // Retry action
-            addAction(R.drawable.ic_refresh_24dp,
-                    context.getString(R.string.action_retry),
-                    UpdaterService.downloadApkPendingService(context, url))
+            addAction(
+                R.drawable.ic_refresh_24dp,
+                context.getString(R.string.action_retry),
+                UpdaterService.downloadApkPendingService(context, url)
+            )
             // Cancel action
-            addAction(R.drawable.ic_close_24dp,
-                    context.getString(R.string.action_cancel),
-                    NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER))
+            addAction(
+                R.drawable.ic_close_24dp,
+                context.getString(R.string.action_cancel),
+                NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)
+            )
         }
         notificationBuilder.show(Notifications.ID_UPDATER)
     }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/updater/devrepo/DevRepoUpdateChecker.kt

@@ -16,8 +16,8 @@ class DevRepoUpdateChecker : UpdateChecker() {
 
     private val client: OkHttpClient by lazy {
         Injekt.get<NetworkHelper>().client.newBuilder()
-                .followRedirects(false)
-                .build()
+            .followRedirects(false)
+            .build()
     }
 
     private val versionRegex: Regex by lazy {

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/updater/github/GithubService.kt

@@ -15,10 +15,10 @@ interface GithubService {
     companion object {
         fun create(): GithubService {
             val restAdapter = Retrofit.Builder()
-                    .baseUrl("https://api.github.com")
-                    .addConverterFactory(GsonConverterFactory.create())
-                    .client(Injekt.get<NetworkHelper>().client)
-                    .build()
+                .baseUrl("https://api.github.com")
+                .addConverterFactory(GsonConverterFactory.create())
+                .client(Injekt.get<NetworkHelper>().client)
+                .build()
 
             return restAdapter.create(GithubService::class.java)
         }

+ 16 - 16
app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt

@@ -119,16 +119,16 @@ class ExtensionManager(
         val extensions = ExtensionLoader.loadExtensions(context)
 
         installedExtensions = extensions
-                .filterIsInstance<LoadResult.Success>()
-                .map { it.extension }
+            .filterIsInstance<LoadResult.Success>()
+            .map { it.extension }
         installedExtensions
-                .flatMap { it.sources }
-                // overwrite is needed until the bundled sources are removed
-                .forEach { sourceManager.registerSource(it, true) }
+            .flatMap { it.sources }
+            // overwrite is needed until the bundled sources are removed
+            .forEach { sourceManager.registerSource(it, true) }
 
         untrustedExtensions = extensions
-                .filterIsInstance<LoadResult.Untrusted>()
-                .map { it.extension }
+            .filterIsInstance<LoadResult.Untrusted>()
+            .map { it.extension }
     }
 
     /**
@@ -223,7 +223,7 @@ class ExtensionManager(
      */
     fun updateExtension(extension: Extension.Installed): Observable<InstallStep> {
         val availableExt = availableExtensions.find { it.pkgName == extension.pkgName }
-                ?: return Observable.empty()
+            ?: return Observable.empty()
         return installExtension(availableExt)
     }
 
@@ -266,15 +266,15 @@ class ExtensionManager(
         val ctx = context
         launchNow {
             nowTrustedExtensions
-                    .map { extension ->
-                        async { ExtensionLoader.loadExtensionFromPkgName(ctx, extension.pkgName) }
-                    }
-                    .map { it.await() }
-                    .forEach { result ->
-                        if (result is LoadResult.Success) {
-                            registerNewExtension(result.extension)
-                        }
+                .map { extension ->
+                    async { ExtensionLoader.loadExtensionFromPkgName(ctx, extension.pkgName) }
+                }
+                .map { it.await() }
+                .forEach { result ->
+                    if (result is LoadResult.Success) {
+                        registerNewExtension(result.extension)
                     }
+                }
         }
     }
 

+ 6 - 3
app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionUpdateJob.kt

@@ -40,7 +40,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
 
     private fun createUpdateNotification(names: List<String>) {
         NotificationManagerCompat.from(context).apply {
-            notify(Notifications.ID_UPDATES_TO_EXTS,
+            notify(
+                Notifications.ID_UPDATES_TO_EXTS,
                 context.notification(Notifications.CHANNEL_UPDATES_TO_EXTS) {
                     setContentTitle(
                         context.resources.getQuantityString(
@@ -55,7 +56,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
                     setSmallIcon(R.drawable.ic_extension_24dp)
                     setContentIntent(NotificationReceiver.openExtensionsPendingActivity(context))
                     setAutoCancel(true)
-                })
+                }
+            )
         }
     }
 
@@ -72,7 +74,8 @@ class ExtensionUpdateJob(private val context: Context, workerParams: WorkerParam
 
                 val request = PeriodicWorkRequestBuilder<ExtensionUpdateJob>(
                     12, TimeUnit.HOURS,
-                    1, TimeUnit.HOURS)
+                    1, TimeUnit.HOURS
+                )
                     .addTag(TAG)
                     .setConstraints(constraints)
                     .build()

+ 16 - 16
app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt

@@ -70,22 +70,22 @@ internal class ExtensionGithubApi {
         val json = gson.fromJson<JsonArray>(text)
 
         return json
-                .filter { element ->
-                    val versionName = element["version"].string
-                    val libVersion = versionName.substringBeforeLast('.').toDouble()
-                    libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX
-                }
-                .map { element ->
-                    val name = element["name"].string.substringAfter("Tachiyomi: ")
-                    val pkgName = element["pkg"].string
-                    val apkName = element["apk"].string
-                    val versionName = element["version"].string
-                    val versionCode = element["code"].int
-                    val lang = element["lang"].string
-                    val icon = "$REPO_URL/icon/${apkName.replace(".apk", ".png")}"
-
-                    Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon)
-                }
+            .filter { element ->
+                val versionName = element["version"].string
+                val libVersion = versionName.substringBeforeLast('.').toDouble()
+                libVersion >= ExtensionLoader.LIB_VERSION_MIN && libVersion <= ExtensionLoader.LIB_VERSION_MAX
+            }
+            .map { element ->
+                val name = element["name"].string.substringAfter("Tachiyomi: ")
+                val pkgName = element["pkg"].string
+                val apkName = element["apk"].string
+                val versionName = element["version"].string
+                val versionCode = element["code"].int
+                val lang = element["lang"].string
+                val icon = "$REPO_URL/icon/${apkName.replace(".apk", ".png")}"
+
+                Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon)
+            }
     }
 
     fun getApkUrl(extension: Extension.Available): String {

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallActivity.kt

@@ -18,9 +18,9 @@ class ExtensionInstallActivity : Activity() {
         super.onCreate(savedInstanceState)
 
         val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
-                .setDataAndType(intent.data, intent.type)
-                .putExtra(Intent.EXTRA_RETURN_RESULT, true)
-                .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            .setDataAndType(intent.data, intent.type)
+            .putExtra(Intent.EXTRA_RETURN_RESULT, true)
+            .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
 
         try {
             startActivityForResult(installIntent, INSTALL_REQUEST_CODE)

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstallReceiver.kt

@@ -19,7 +19,7 @@ import kotlinx.coroutines.async
  * @param listener The listener that should be notified of extension installation events.
  */
 internal class ExtensionInstallReceiver(private val listener: Listener) :
-        BroadcastReceiver() {
+    BroadcastReceiver() {
 
     /**
      * Registers this broadcast receiver
@@ -93,7 +93,7 @@ internal class ExtensionInstallReceiver(private val listener: Listener) :
      */
     private suspend fun getExtensionFromIntent(context: Context, intent: Intent?): LoadResult {
         val pkgName = getPackageNameFromIntent(intent)
-                ?: return LoadResult.Error("Package name not found")
+            ?: return LoadResult.Error("Package name not found")
         return GlobalScope.async(Dispatchers.Default, CoroutineStart.DEFAULT) { ExtensionLoader.loadExtensionFromPkgName(context, pkgName) }.await()
     }
 

+ 37 - 37
app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionInstaller.kt

@@ -65,26 +65,26 @@ internal class ExtensionInstaller(private val context: Context) {
 
         val downloadUri = Uri.parse(url)
         val request = DownloadManager.Request(downloadUri)
-                .setTitle(extension.name)
-                .setMimeType(APK_MIME)
-                .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment)
-                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
+            .setTitle(extension.name)
+            .setMimeType(APK_MIME)
+            .setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, downloadUri.lastPathSegment)
+            .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
 
         val id = downloadManager.enqueue(request)
         activeDownloads[pkgName] = id
 
         downloadsRelay.filter { it.first == id }
-                .map { it.second }
-                // Poll download status
-                .mergeWith(pollStatus(id))
-                // Force an error if the download takes more than 3 minutes
-                .mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
-                // Stop when the application is installed or errors
-                .takeUntil { it.isCompleted() }
-                // Always notify on main thread
-                .observeOn(AndroidSchedulers.mainThread())
-                // Always remove the download when unsubscribed
-                .doOnUnsubscribe { deleteDownload(pkgName) }
+            .map { it.second }
+            // Poll download status
+            .mergeWith(pollStatus(id))
+            // Force an error if the download takes more than 3 minutes
+            .mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
+            // Stop when the application is installed or errors
+            .takeUntil { it.isCompleted() }
+            // Always notify on main thread
+            .observeOn(AndroidSchedulers.mainThread())
+            // Always remove the download when unsubscribed
+            .doOnUnsubscribe { deleteDownload(pkgName) }
     }
 
     /**
@@ -97,25 +97,25 @@ internal class ExtensionInstaller(private val context: Context) {
         val query = DownloadManager.Query().setFilterById(id)
 
         return Observable.interval(0, 1, TimeUnit.SECONDS)
-                // Get the current download status
-                .map {
-                    downloadManager.query(query).use { cursor ->
-                        cursor.moveToFirst()
-                        cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
-                    }
+            // Get the current download status
+            .map {
+                downloadManager.query(query).use { cursor ->
+                    cursor.moveToFirst()
+                    cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                 }
-                // Ignore duplicate results
-                .distinctUntilChanged()
-                // Stop polling when the download fails or finishes
-                .takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED }
-                // Map to our model
-                .flatMap { status ->
-                    when (status) {
-                        DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending)
-                        DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading)
-                        else -> Observable.empty()
-                    }
+            }
+            // Ignore duplicate results
+            .distinctUntilChanged()
+            // Stop polling when the download fails or finishes
+            .takeUntil { it == DownloadManager.STATUS_SUCCESSFUL || it == DownloadManager.STATUS_FAILED }
+            // Map to our model
+            .flatMap { status ->
+                when (status) {
+                    DownloadManager.STATUS_PENDING -> Observable.just(InstallStep.Pending)
+                    DownloadManager.STATUS_RUNNING -> Observable.just(InstallStep.Downloading)
+                    else -> Observable.empty()
                 }
+            }
     }
 
     /**
@@ -125,9 +125,9 @@ internal class ExtensionInstaller(private val context: Context) {
      */
     fun installApk(downloadId: Long, uri: Uri) {
         val intent = Intent(context, ExtensionInstallActivity::class.java)
-                .setDataAndType(uri, APK_MIME)
-                .putExtra(EXTRA_DOWNLOAD_ID, downloadId)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            .setDataAndType(uri, APK_MIME)
+            .putExtra(EXTRA_DOWNLOAD_ID, downloadId)
+            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
 
         context.startActivity(intent)
     }
@@ -140,7 +140,7 @@ internal class ExtensionInstaller(private val context: Context) {
     fun uninstallApk(pkgName: String) {
         val packageUri = Uri.parse("package:$pkgName")
         val intent = Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
 
         context.startActivity(intent)
     }
@@ -227,7 +227,7 @@ internal class ExtensionInstaller(private val context: Context) {
             downloadManager.query(query).use { cursor ->
                 if (cursor.moveToFirst()) {
                     val localUri = cursor.getString(
-                            cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
+                        cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)
                     ).removePrefix(FILE_SCHEME)
 
                     installApk(id, File(localUri).getUriCompat(context))

+ 27 - 24
app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt

@@ -35,9 +35,9 @@ internal object ExtensionLoader {
      * List of the trusted signatures.
      */
     var trustedSignatures = mutableSetOf<String>() +
-            Injekt.get<PreferencesHelper>().trustedSignatures().get() +
-            // inorichi's key
-            "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23"
+        Injekt.get<PreferencesHelper>().trustedSignatures().get() +
+        // inorichi's key
+        "7ce04da7773d41b489f4693a366c36bcd0a11fc39b547168553c285bd7348e23"
 
     /**
      * Return a list of all the installed extensions initialized concurrently.
@@ -107,8 +107,10 @@ internal object ExtensionLoader {
         // Validate lib version
         val libVersion = versionName.substringBeforeLast('.').toDouble()
         if (libVersion < LIB_VERSION_MIN || libVersion > LIB_VERSION_MAX) {
-            val exception = Exception("Lib version is $libVersion, while only versions " +
-                    "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed")
+            val exception = Exception(
+                "Lib version is $libVersion, while only versions " +
+                    "$LIB_VERSION_MIN to $LIB_VERSION_MAX are allowed"
+            )
             Timber.w(exception)
             return LoadResult.Error(exception)
         }
@@ -126,29 +128,30 @@ internal object ExtensionLoader {
         val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
 
         val sources = appInfo.metaData.getString(METADATA_SOURCE_CLASS)!!
-                .split(";")
-                .map {
-                    val sourceClass = it.trim()
-                    if (sourceClass.startsWith("."))
-                        pkgInfo.packageName + sourceClass
-                    else
-                        sourceClass
+            .split(";")
+            .map {
+                val sourceClass = it.trim()
+                if (sourceClass.startsWith(".")) {
+                    pkgInfo.packageName + sourceClass
+                } else {
+                    sourceClass
                 }
-                .flatMap {
-                    try {
-                        when (val obj = Class.forName(it, false, classLoader).newInstance()) {
-                            is Source -> listOf(obj)
-                            is SourceFactory -> obj.createSources()
-                            else -> throw Exception("Unknown source class type! ${obj.javaClass}")
-                        }
-                    } catch (e: Throwable) {
-                        Timber.e(e, "Extension load error: $extName.")
-                        return LoadResult.Error(e)
+            }
+            .flatMap {
+                try {
+                    when (val obj = Class.forName(it, false, classLoader).newInstance()) {
+                        is Source -> listOf(obj)
+                        is SourceFactory -> obj.createSources()
+                        else -> throw Exception("Unknown source class type! ${obj.javaClass}")
                     }
+                } catch (e: Throwable) {
+                    Timber.e(e, "Extension load error: $extName.")
+                    return LoadResult.Error(e)
                 }
+            }
         val langs = sources.filterIsInstance<CatalogueSource>()
-                .map { it.lang }
-                .toSet()
+            .map { it.lang }
+            .toSet()
 
         val lang = when (langs.size) {
             0 -> ""

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/network/AndroidCookieJar.kt

@@ -44,9 +44,9 @@ class AndroidCookieJar : CookieJar {
         }
 
         cookies.split(";")
-                .map { it.substringBefore("=") }
-                .filterNames()
-                .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") }
+            .map { it.substringBefore("=") }
+            .filterNames()
+            .onEach { manager.setCookie(urlString, "$it=;Max-Age=$maxAge") }
     }
 
     fun removeAll() {

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/network/CloudflareInterceptor.kt

@@ -54,7 +54,7 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
             response.close()
             networkHelper.cookieManager.remove(originalRequest.url, COOKIE_NAMES, 0)
             val oldCookie = networkHelper.cookieManager.get(originalRequest.url)
-                    .firstOrNull { it.name == "cf_clearance" }
+                .firstOrNull { it.name == "cf_clearance" }
             resolveWithWebView(originalRequest, oldCookie)
 
             return chain.proceed(originalRequest)
@@ -87,14 +87,14 @@ class CloudflareInterceptor(private val context: Context) : Interceptor {
 
             // Avoid set empty User-Agent, Chromium WebView will reset to default if empty
             webview.settings.userAgentString = request.header("User-Agent")
-                    ?: HttpSource.DEFAULT_USERAGENT
+                ?: HttpSource.DEFAULT_USERAGENT
 
             webview.webViewClient = object : WebViewClientCompat() {
                 override fun onPageFinished(view: WebView, url: String) {
                     fun isCloudFlareBypassed(): Boolean {
                         return networkHelper.cookieManager.get(origRequestUrl.toHttpUrl())
-                                .firstOrNull { it.name == "cf_clearance" }
-                                .let { it != null && it != oldCookie }
+                            .firstOrNull { it.name == "cf_clearance" }
+                            .let { it != null && it != oldCookie }
                     }
 
                     if (isCloudFlareBypassed()) {

+ 6 - 6
app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt

@@ -14,12 +14,12 @@ class NetworkHelper(context: Context) {
     val cookieManager = AndroidCookieJar()
 
     val client = OkHttpClient.Builder()
-            .cookieJar(cookieManager)
-            .cache(Cache(cacheDir, cacheSize))
-            .build()
+        .cookieJar(cookieManager)
+        .cache(Cache(cacheDir, cacheSize))
+        .build()
 
     val cloudflareClient = client.newBuilder()
-            .addInterceptor(UserAgentInterceptor())
-            .addInterceptor(CloudflareInterceptor(context))
-            .build()
+        .addInterceptor(UserAgentInterceptor())
+        .addInterceptor(CloudflareInterceptor(context))
+        .build()
 }

+ 8 - 8
app/src/main/java/eu/kanade/tachiyomi/network/OkHttpExtensions.kt

@@ -92,14 +92,14 @@ fun Call.asObservableSuccess(): Observable<Response> {
 
 fun OkHttpClient.newCallWithProgress(request: Request, listener: ProgressListener): Call {
     val progressClient = newBuilder()
-            .cache(null)
-            .addNetworkInterceptor { chain ->
-                val originalResponse = chain.proceed(chain.request())
-                originalResponse.newBuilder()
-                        .body(ProgressResponseBody(originalResponse.body!!, listener))
-                        .build()
-            }
-            .build()
+        .cache(null)
+        .addNetworkInterceptor { chain ->
+            val originalResponse = chain.proceed(chain.request())
+            originalResponse.newBuilder()
+                .body(ProgressResponseBody(originalResponse.body!!, listener))
+                .build()
+        }
+        .build()
 
     return progressClient.newCall(request)
 }

+ 9 - 9
app/src/main/java/eu/kanade/tachiyomi/network/Requests.kt

@@ -17,10 +17,10 @@ fun GET(
     cache: CacheControl = DEFAULT_CACHE_CONTROL
 ): Request {
     return Request.Builder()
-            .url(url)
-            .headers(headers)
-            .cacheControl(cache)
-            .build()
+        .url(url)
+        .headers(headers)
+        .cacheControl(cache)
+        .build()
 }
 
 fun POST(
@@ -30,9 +30,9 @@ fun POST(
     cache: CacheControl = DEFAULT_CACHE_CONTROL
 ): Request {
     return Request.Builder()
-            .url(url)
-            .post(body)
-            .headers(headers)
-            .cacheControl(cache)
-            .build()
+        .url(url)
+        .post(body)
+        .headers(headers)
+        .cacheControl(cache)
+        .build()
 }

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/network/UserAgentInterceptor.kt

@@ -10,10 +10,10 @@ class UserAgentInterceptor : Interceptor {
 
         return if (originalRequest.header("User-Agent").isNullOrEmpty()) {
             val newRequest = originalRequest
-                    .newBuilder()
-                    .removeHeader("User-Agent")
-                    .addHeader("User-Agent", HttpSource.DEFAULT_USERAGENT)
-                    .build()
+                .newBuilder()
+                .removeHeader("User-Agent")
+                .addHeader("User-Agent", HttpSource.DEFAULT_USERAGENT)
+                .build()
             chain.proceed(newRequest)
         } else {
             chain.proceed(originalRequest)

+ 51 - 47
app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt

@@ -76,23 +76,25 @@ class LocalSource(private val context: Context) : CatalogueSource {
 
         val time = if (filters === LATEST_FILTERS) System.currentTimeMillis() - LATEST_THRESHOLD else 0L
         var mangaDirs = baseDirs.mapNotNull { it.listFiles()?.toList() }
-                .flatten()
-                .filter { it.isDirectory && if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time }
-                .distinctBy { it.name }
+            .flatten()
+            .filter { it.isDirectory && if (time == 0L) it.name.contains(query, ignoreCase = true) else it.lastModified() >= time }
+            .distinctBy { it.name }
 
         val state = ((if (filters.isEmpty()) POPULAR_FILTERS else filters)[0] as OrderBy).state
         when (state?.index) {
             0 -> {
-                mangaDirs = if (state.ascending)
+                mangaDirs = if (state.ascending) {
                     mangaDirs.sortedBy { it.name.toLowerCase(Locale.ENGLISH) }
-                else
+                } else {
                     mangaDirs.sortedByDescending { it.name.toLowerCase(Locale.ENGLISH) }
+                }
             }
             1 -> {
-                mangaDirs = if (state.ascending)
+                mangaDirs = if (state.ascending) {
                     mangaDirs.sortedBy(File::lastModified)
-                else
+                } else {
                     mangaDirs.sortedByDescending(File::lastModified)
+                }
             }
         }
 
@@ -131,47 +133,49 @@ class LocalSource(private val context: Context) : CatalogueSource {
 
     override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
         getBaseDirectories(context)
-                .mapNotNull { File(it, manga.url).listFiles()?.toList() }
-                .flatten()
-                .firstOrNull { it.extension == "json" }
-                ?.apply {
-                    val json = Gson().fromJson(Scanner(this).useDelimiter("\\Z").next(), JsonObject::class.java)
-                    manga.title = json["title"]?.asString ?: manga.title
-                    manga.author = json["author"]?.asString ?: manga.author
-                    manga.artist = json["artist"]?.asString ?: manga.artist
-                    manga.description = json["description"]?.asString ?: manga.description
-                    manga.genre = json["genre"]?.asJsonArray?.joinToString(", ") { it.asString }
-                            ?: manga.genre
-                    manga.status = json["status"]?.asInt ?: manga.status
-                }
+            .mapNotNull { File(it, manga.url).listFiles()?.toList() }
+            .flatten()
+            .firstOrNull { it.extension == "json" }
+            ?.apply {
+                val json = Gson().fromJson(Scanner(this).useDelimiter("\\Z").next(), JsonObject::class.java)
+                manga.title = json["title"]?.asString ?: manga.title
+                manga.author = json["author"]?.asString ?: manga.author
+                manga.artist = json["artist"]?.asString ?: manga.artist
+                manga.description = json["description"]?.asString ?: manga.description
+                manga.genre = json["genre"]?.asJsonArray?.joinToString(", ") { it.asString }
+                    ?: manga.genre
+                manga.status = json["status"]?.asInt ?: manga.status
+            }
         return Observable.just(manga)
     }
 
     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
         val chapters = getBaseDirectories(context)
-                .asSequence()
-                .mapNotNull { File(it, manga.url).listFiles()?.toList() }
-                .flatten()
-                .filter { it.isDirectory || isSupportedFile(it.extension) }
-                .map { chapterFile ->
-                    SChapter.create().apply {
-                        url = "${manga.url}/${chapterFile.name}"
-                        val chapName = if (chapterFile.isDirectory) {
-                            chapterFile.name
-                        } else {
-                            chapterFile.nameWithoutExtension
-                        }
-                        val chapNameCut = chapName.replace(manga.title, "", true).trim(' ', '-', '_')
-                        name = if (chapNameCut.isEmpty()) chapName else chapNameCut
-                        date_upload = chapterFile.lastModified()
-                        ChapterRecognition.parseChapterNumber(this, manga)
+            .asSequence()
+            .mapNotNull { File(it, manga.url).listFiles()?.toList() }
+            .flatten()
+            .filter { it.isDirectory || isSupportedFile(it.extension) }
+            .map { chapterFile ->
+                SChapter.create().apply {
+                    url = "${manga.url}/${chapterFile.name}"
+                    val chapName = if (chapterFile.isDirectory) {
+                        chapterFile.name
+                    } else {
+                        chapterFile.nameWithoutExtension
                     }
+                    val chapNameCut = chapName.replace(manga.title, "", true).trim(' ', '-', '_')
+                    name = if (chapNameCut.isEmpty()) chapName else chapNameCut
+                    date_upload = chapterFile.lastModified()
+                    ChapterRecognition.parseChapterNumber(this, manga)
                 }
-                .sortedWith(Comparator { c1, c2 ->
+            }
+            .sortedWith(
+                Comparator { c1, c2 ->
                     val c = c2.chapter_number.compareTo(c1.chapter_number)
                     if (c == 0) c2.name.compareToCaseInsensitiveNaturalOrder(c1.name) else c
-                })
-                .toList()
+                }
+            )
+            .toList()
 
         return Observable.just(chapters)
     }
@@ -215,16 +219,16 @@ class LocalSource(private val context: Context) : CatalogueSource {
         return when (val format = getFormat(chapter)) {
             is Format.Directory -> {
                 val entry = format.file.listFiles()
-                        .sortedWith(Comparator<File> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
-                        .find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
+                    .sortedWith(Comparator<File> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
+                    .find { !it.isDirectory && ImageUtil.isImage(it.name) { FileInputStream(it) } }
 
                 entry?.let { updateCover(context, manga, it.inputStream()) }
             }
             is Format.Zip -> {
                 ZipFile(format.file).use { zip ->
                     val entry = zip.entries().toList()
-                            .sortedWith(Comparator<ZipEntry> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
-                            .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
+                        .sortedWith(Comparator<ZipEntry> { f1, f2 -> f1.name.compareToCaseInsensitiveNaturalOrder(f2.name) })
+                        .find { !it.isDirectory && ImageUtil.isImage(it.name) { zip.getInputStream(it) } }
 
                     entry?.let { updateCover(context, manga, zip.getInputStream(it)) }
                 }
@@ -232,8 +236,8 @@ class LocalSource(private val context: Context) : CatalogueSource {
             is Format.Rar -> {
                 Archive(format.file).use { archive ->
                     val entry = archive.fileHeaders
-                            .sortedWith(Comparator<FileHeader> { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) })
-                            .find { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } }
+                        .sortedWith(Comparator<FileHeader> { f1, f2 -> f1.fileNameString.compareToCaseInsensitiveNaturalOrder(f2.fileNameString) })
+                        .find { !it.isDirectory && ImageUtil.isImage(it.fileNameString) { archive.getInputStream(it) } }
 
                     entry?.let { updateCover(context, manga, archive.getInputStream(it)) }
                 }
@@ -241,8 +245,8 @@ class LocalSource(private val context: Context) : CatalogueSource {
             is Format.Epub -> {
                 EpubFile(format.file).use { epub ->
                     val entry = epub.getImagesFromPages()
-                            .firstOrNull()
-                            ?.let { epub.getEntry(it) }
+                        .firstOrNull()
+                        ?.let { epub.getEntry(it) }
 
                     entry?.let { updateCover(context, manga, epub.getInputStream(it)) }
                 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt

@@ -46,7 +46,7 @@ open class SourceManager(private val context: Context) {
     }
 
     private fun createInternalSources(): List<Source> = listOf(
-            LocalSource(context)
+        LocalSource(context)
     )
 
     private inner class StubSource(override val id: Long) : Source {

+ 12 - 6
app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt

@@ -23,25 +23,31 @@ interface SManga : Serializable {
     var initialized: Boolean
 
     fun copyFrom(other: SManga) {
-        if (other.author != null)
+        if (other.author != null) {
             author = other.author
+        }
 
-        if (other.artist != null)
+        if (other.artist != null) {
             artist = other.artist
+        }
 
-        if (other.description != null)
+        if (other.description != null) {
             description = other.description
+        }
 
-        if (other.genre != null)
+        if (other.genre != null) {
             genre = other.genre
+        }
 
-        if (other.thumbnail_url != null)
+        if (other.thumbnail_url != null) {
             thumbnail_url = other.thumbnail_url
+        }
 
         status = other.status
 
-        if (!initialized)
+        if (!initialized) {
             initialized = other.initialized
+        }
     }
 
     companion object {

+ 31 - 29
app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSource.kt

@@ -90,10 +90,10 @@ abstract class HttpSource : CatalogueSource {
      */
     override fun fetchPopularManga(page: Int): Observable<MangasPage> {
         return client.newCall(popularMangaRequest(page))
-                .asObservableSuccess()
-                .map { response ->
-                    popularMangaParse(response)
-                }
+            .asObservableSuccess()
+            .map { response ->
+                popularMangaParse(response)
+            }
     }
 
     /**
@@ -120,10 +120,10 @@ abstract class HttpSource : CatalogueSource {
      */
     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
         return client.newCall(searchMangaRequest(page, query, filters))
-                .asObservableSuccess()
-                .map { response ->
-                    searchMangaParse(response)
-                }
+            .asObservableSuccess()
+            .map { response ->
+                searchMangaParse(response)
+            }
     }
 
     /**
@@ -149,10 +149,10 @@ abstract class HttpSource : CatalogueSource {
      */
     override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
         return client.newCall(latestUpdatesRequest(page))
-                .asObservableSuccess()
-                .map { response ->
-                    latestUpdatesParse(response)
-                }
+            .asObservableSuccess()
+            .map { response ->
+                latestUpdatesParse(response)
+            }
     }
 
     /**
@@ -177,10 +177,10 @@ abstract class HttpSource : CatalogueSource {
      */
     override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
         return client.newCall(mangaDetailsRequest(manga))
-                .asObservableSuccess()
-                .map { response ->
-                    mangaDetailsParse(response).apply { initialized = true }
-                }
+            .asObservableSuccess()
+            .map { response ->
+                mangaDetailsParse(response).apply { initialized = true }
+            }
     }
 
     /**
@@ -209,10 +209,10 @@ abstract class HttpSource : CatalogueSource {
     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
         return if (manga.status != SManga.LICENSED) {
             client.newCall(chapterListRequest(manga))
-                    .asObservableSuccess()
-                    .map { response ->
-                        chapterListParse(response)
-                    }
+                .asObservableSuccess()
+                .map { response ->
+                    chapterListParse(response)
+                }
         } else {
             Observable.error(Exception("Licensed - No chapters to show"))
         }
@@ -242,10 +242,10 @@ abstract class HttpSource : CatalogueSource {
      */
     override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
         return client.newCall(pageListRequest(chapter))
-                .asObservableSuccess()
-                .map { response ->
-                    pageListParse(response)
-                }
+            .asObservableSuccess()
+            .map { response ->
+                pageListParse(response)
+            }
     }
 
     /**
@@ -273,8 +273,8 @@ abstract class HttpSource : CatalogueSource {
      */
     open fun fetchImageUrl(page: Page): Observable<String> {
         return client.newCall(imageUrlRequest(page))
-                .asObservableSuccess()
-                .map { imageUrlParse(it) }
+            .asObservableSuccess()
+            .map { imageUrlParse(it) }
     }
 
     /**
@@ -301,7 +301,7 @@ abstract class HttpSource : CatalogueSource {
      */
     fun fetchImage(page: Page): Observable<Response> {
         return client.newCallWithProgress(imageRequest(page), page)
-                .asObservableSuccess()
+            .asObservableSuccess()
     }
 
     /**
@@ -343,10 +343,12 @@ abstract class HttpSource : CatalogueSource {
         return try {
             val uri = URI(orig)
             var out = uri.path
-            if (uri.query != null)
+            if (uri.query != null) {
                 out += "?" + uri.query
-            if (uri.fragment != null)
+            }
+            if (uri.fragment != null) {
                 out += "#" + uri.fragment
+            }
             out
         } catch (e: URISyntaxException) {
             orig

+ 8 - 8
app/src/main/java/eu/kanade/tachiyomi/source/online/HttpSourceFetcher.kt

@@ -6,20 +6,20 @@ import rx.Observable
 fun HttpSource.getImageUrl(page: Page): Observable<Page> {
     page.status = Page.LOAD_PAGE
     return fetchImageUrl(page)
-            .doOnError { page.status = Page.ERROR }
-            .onErrorReturn { null }
-            .doOnNext { page.imageUrl = it }
-            .map { page }
+        .doOnError { page.status = Page.ERROR }
+        .onErrorReturn { null }
+        .doOnNext { page.imageUrl = it }
+        .map { page }
 }
 
 fun HttpSource.fetchAllImageUrlsFromPageList(pages: List<Page>): Observable<Page> {
     return Observable.from(pages)
-            .filter { !it.imageUrl.isNullOrEmpty() }
-            .mergeWith(fetchRemainingImageUrlsFromPageList(pages))
+        .filter { !it.imageUrl.isNullOrEmpty() }
+        .mergeWith(fetchRemainingImageUrlsFromPageList(pages))
 }
 
 fun HttpSource.fetchRemainingImageUrlsFromPageList(pages: List<Page>): Observable<Page> {
     return Observable.from(pages)
-            .filter { it.imageUrl.isNullOrEmpty() }
-            .concatMap { getImageUrl(it) }
+        .filter { it.imageUrl.isNullOrEmpty() }
+        .concatMap { getImageUrl(it) }
 }

+ 11 - 9
app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseActivity.kt

@@ -59,17 +59,19 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {
-        setTheme(when (preferences.themeMode().get()) {
-            Values.THEME_MODE_SYSTEM -> {
-                if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
-                    darkTheme
-                } else {
-                    lightTheme
+        setTheme(
+            when (preferences.themeMode().get()) {
+                Values.THEME_MODE_SYSTEM -> {
+                    if (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) {
+                        darkTheme
+                    } else {
+                        lightTheme
+                    }
                 }
+                Values.THEME_MODE_DARK -> darkTheme
+                else -> lightTheme
             }
-            Values.THEME_MODE_DARK -> darkTheme
-            else -> lightTheme
-        })
+        )
 
         super.onCreate(savedInstanceState)
 

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/BaseController.kt

@@ -15,8 +15,9 @@ import kotlinx.android.extensions.LayoutContainer
 import kotlinx.android.synthetic.clearFindViewByIdCache
 import timber.log.Timber
 
-abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle),
-        LayoutContainer {
+abstract class BaseController<VB : ViewBinding>(bundle: Bundle? = null) :
+    RestoreViewOnCreateController(bundle),
+    LayoutContainer {
 
     lateinit var binding: VB
 

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/ConductorExtensions.kt

@@ -30,6 +30,6 @@ fun Controller.requestPermissionsSafe(permissions: Array<String>, requestCode: I
 
 fun Controller.withFadeTransaction(): RouterTransaction {
     return RouterTransaction.with(this)
-            .pushChangeHandler(FadeChangeHandler())
-            .popChangeHandler(FadeChangeHandler())
+        .pushChangeHandler(FadeChangeHandler())
+        .popChangeHandler(FadeChangeHandler())
 }

+ 4 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/DialogController.kt

@@ -87,10 +87,12 @@ abstract class DialogController : RestoreViewOnCreateController {
      */
     fun showDialog(router: Router, tag: String?) {
         dismissed = false
-        router.pushController(RouterTransaction.with(this)
+        router.pushController(
+            RouterTransaction.with(this)
                 .pushChangeHandler(SimpleSwapChangeHandler(false))
                 .popChangeHandler(SimpleSwapChangeHandler(false))
-                .tag(tag))
+                .tag(tag)
+        )
     }
 
     /**

+ 0 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/base/controller/RxController.kt

@@ -44,12 +44,10 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
     }
 
     fun <T> Observable<T>.subscribeUntilDetach(): Subscription {
-
         return subscribe().also { untilDetachSubscriptions.add(it) }
     }
 
     fun <T> Observable<T>.subscribeUntilDetach(onNext: (T) -> Unit): Subscription {
-
         return subscribe(onNext).also { untilDetachSubscriptions.add(it) }
     }
 
@@ -57,7 +55,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
         onNext: (T) -> Unit,
         onError: (Throwable) -> Unit
     ): Subscription {
-
         return subscribe(onNext, onError).also { untilDetachSubscriptions.add(it) }
     }
 
@@ -66,17 +63,14 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
         onError: (Throwable) -> Unit,
         onCompleted: () -> Unit
     ): Subscription {
-
         return subscribe(onNext, onError, onCompleted).also { untilDetachSubscriptions.add(it) }
     }
 
     fun <T> Observable<T>.subscribeUntilDestroy(): Subscription {
-
         return subscribe().also { untilDestroySubscriptions.add(it) }
     }
 
     fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
-
         return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
     }
 
@@ -84,7 +78,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
         onNext: (T) -> Unit,
         onError: (Throwable) -> Unit
     ): Subscription {
-
         return subscribe(onNext, onError).also { untilDestroySubscriptions.add(it) }
     }
 
@@ -93,7 +86,6 @@ abstract class RxController<VB : ViewBinding>(bundle: Bundle? = null) : BaseCont
         onError: (Throwable) -> Unit,
         onCompleted: () -> Unit
     ): Subscription {
-
         return subscribe(onNext, onError, onCompleted).also { untilDestroySubscriptions.add(it) }
     }
 }

+ 5 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt

@@ -59,11 +59,11 @@ open class BasePresenter<V> : RxPresenter<V>() {
 
         override fun call(observable: Observable<T>): Observable<Delivery<View, T>> {
             return observable
-                    .materialize()
-                    .filter { notification -> !notification.isOnCompleted }
-                    .flatMap { notification ->
-                        view.take(1).filter { it != null }.map { Delivery(it, notification) }
-                    }
+                .materialize()
+                .filter { notification -> !notification.isOnCompleted }
+                .flatMap { notification ->
+                    view.take(1).filter { it != null }.map { Delivery(it, notification) }
+                }
         }
     }
 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt

@@ -8,7 +8,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
  * @param controller The containing controller.
  */
 class CategoryAdapter(controller: CategoryController) :
-        FlexibleAdapter<CategoryItem>(null, controller, true) {
+    FlexibleAdapter<CategoryItem>(null, controller, true) {
 
     /**
      * Listener called when an item of the list is released.

+ 13 - 10
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryController.kt

@@ -25,14 +25,15 @@ import reactivecircus.flowbinding.android.view.clicks
 /**
  * Controller to manage the categories for the users' library.
  */
-class CategoryController : NucleusController<CategoriesControllerBinding, CategoryPresenter>(),
-        ActionMode.Callback,
-        FlexibleAdapter.OnItemClickListener,
-        FlexibleAdapter.OnItemLongClickListener,
-        CategoryAdapter.OnItemReleaseListener,
-        CategoryCreateDialog.Listener,
-        CategoryRenameDialog.Listener,
-        UndoHelper.OnActionListener {
+class CategoryController :
+    NucleusController<CategoriesControllerBinding, CategoryPresenter>(),
+    ActionMode.Callback,
+    FlexibleAdapter.OnItemClickListener,
+    FlexibleAdapter.OnItemLongClickListener,
+    CategoryAdapter.OnItemReleaseListener,
+    CategoryCreateDialog.Listener,
+    CategoryRenameDialog.Listener,
+    UndoHelper.OnActionListener {
 
     /**
      * Object used to show ActionMode toolbar.
@@ -176,8 +177,10 @@ class CategoryController : NucleusController<CategoriesControllerBinding, Catego
         when (item.itemId) {
             R.id.action_delete -> {
                 undoHelper = UndoHelper(adapter, this)
-                undoHelper?.start(adapter.selectedPositions, view!!,
-                        R.string.snack_categories_deleted, R.string.action_undo, 3000)
+                undoHelper?.start(
+                    adapter.selectedPositions, view!!,
+                    R.string.snack_categories_deleted, R.string.action_undo, 3000
+                )
 
                 mode.finish()
             }

+ 11 - 11
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryCreateDialog.kt

@@ -31,17 +31,17 @@ class CategoryCreateDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
      */
     override fun onCreateDialog(savedViewState: Bundle?): Dialog {
         return MaterialDialog(activity!!)
-                .title(R.string.action_add_category)
-                .negativeButton(android.R.string.cancel)
-                .input(
-                    hint = resources?.getString(R.string.name),
-                    prefill = currentName
-                ) { _, input ->
-                    currentName = input.toString()
-                }
-                .positiveButton(android.R.string.ok) {
-                    (targetController as? Listener)?.createCategory(currentName)
-                }
+            .title(R.string.action_add_category)
+            .negativeButton(android.R.string.cancel)
+            .input(
+                hint = resources?.getString(R.string.name),
+                prefill = currentName
+            ) { _, input ->
+                currentName = input.toString()
+            }
+            .positiveButton(android.R.string.ok) {
+                (targetController as? Listener)?.createCategory(currentName)
+            }
     }
 
     interface Listener {

Деякі файли не було показано, через те що забагато файлів було змінено