Browse Source

Fix dependency injection and use custom models extending DB ones

len 10 năm trước cách đây
mục cha
commit
237af4b07d
53 tập tin đã thay đổi với 696 bổ sung644 xóa
  1. 7 24
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt
  2. 10 10
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
  3. 3 5
      app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt
  4. 5 7
      app/src/main/java/eu/kanade/tachiyomi/data/glide/AppGlideModule.kt
  5. 4 9
      app/src/main/java/eu/kanade/tachiyomi/data/glide/MangaModelLoader.kt
  6. 5 6
      app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt
  7. 3 8
      app/src/main/java/eu/kanade/tachiyomi/data/mangasync/MangaSyncService.kt
  8. 3 5
      app/src/main/java/eu/kanade/tachiyomi/data/mangasync/UpdateMangaSyncService.kt
  9. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/mangasync/myanimelist/MyAnimeList.kt
  10. 4 10
      app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java
  11. 14 10
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt
  12. 2 4
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt
  13. 5 7
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt
  14. 4 6
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt
  15. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Kissmanga.kt
  16. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt
  17. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt
  18. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt
  19. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Mangachan.kt
  20. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Mintmanga.kt
  21. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Readmanga.kt
  22. 2 6
      app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloader.kt
  23. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/backup/BackupPresenter.kt
  24. 0 1
      app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt
  25. 0 1
      app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt
  26. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt
  27. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt
  28. 5 5
      app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt
  29. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt
  30. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt
  31. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadFragment.kt
  32. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt
  33. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt
  34. 7 7
      app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
  35. 2 5
      app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
  36. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
  37. 19 0
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterModel.kt
  38. 3 4
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt
  39. 11 12
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt
  40. 29 36
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersHolder.kt
  41. 230 75
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt
  42. 6 1
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt
  43. 4 4
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt
  44. 4 4
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListPresenter.kt
  45. 22 0
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapter.kt
  46. 6 6
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt
  47. 82 83
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt
  48. 49 50
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersHolder.kt
  49. 94 178
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt
  50. 3 4
      app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/SectionViewHolder.kt
  51. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt
  52. 2 2
      app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt
  53. 7 9
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt

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

@@ -1,14 +1,13 @@
 package eu.kanade.tachiyomi.data.backup
 
+import com.github.salomonbrys.kotson.fromJson
 import com.google.gson.*
-import com.google.gson.reflect.TypeToken
 import com.google.gson.stream.JsonReader
 import eu.kanade.tachiyomi.data.backup.serializer.IdExclusion
 import eu.kanade.tachiyomi.data.backup.serializer.IntegerSerializer
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.*
 import java.io.*
-import java.lang.reflect.Type
 import java.util.*
 
 /**
@@ -191,8 +190,7 @@ class BackupManager(private val db: DatabaseHelper) {
     private fun restoreCategories(jsonCategories: JsonArray) {
         // Get categories from file and from db
         val dbCategories = db.getCategories().executeAsBlocking()
-        val backupCategories = getArrayOrEmpty<Category>(jsonCategories,
-                object : TypeToken<List<Category>>() {}.type)
+        val backupCategories = gson.fromJson<List<CategoryImpl>>(jsonCategories)
 
         // Iterate over them
         for (category in backupCategories) {
@@ -224,17 +222,13 @@ class BackupManager(private val db: DatabaseHelper) {
      * @param jsonMangas the mangas and its related data (chapters, sync, categories) from the json.
      */
     private fun restoreMangas(jsonMangas: JsonArray) {
-        val chapterToken = object : TypeToken<List<Chapter>>() {}.type
-        val mangaSyncToken = object : TypeToken<List<MangaSync>>() {}.type
-        val categoriesNamesToken = object : TypeToken<List<String>>() {}.type
-
         for (backupManga in jsonMangas) {
             // Map every entry to objects
             val element = backupManga.asJsonObject
-            val manga = gson.fromJson(element.get(MANGA), Manga::class.java)
-            val chapters = getArrayOrEmpty<Chapter>(element.get(CHAPTERS), chapterToken)
-            val sync = getArrayOrEmpty<MangaSync>(element.get(MANGA_SYNC), mangaSyncToken)
-            val categories = getArrayOrEmpty<String>(element.get(CATEGORIES), categoriesNamesToken)
+            val manga = gson.fromJson(element.get(MANGA), MangaImpl::class.java)
+            val chapters = gson.fromJson<List<ChapterImpl>>(element.get(CHAPTERS) ?: JsonArray())
+            val sync = gson.fromJson<List<MangaSyncImpl>>(element.get(MANGA_SYNC) ?: JsonArray())
+            val categories = gson.fromJson<List<String>>(element.get(CATEGORIES) ?: JsonArray())
 
             // Restore everything related to this manga
             restoreManga(manga)
@@ -340,7 +334,7 @@ class BackupManager(private val db: DatabaseHelper) {
     private fun restoreSyncForManga(manga: Manga, sync: List<MangaSync>) {
         // Fix foreign keys with the current manga id
         for (mangaSync in sync) {
-            mangaSync.manga_id = manga.id
+            mangaSync.manga_id = manga.id!!
         }
 
         val dbSyncs = db.getMangasSync(manga).executeAsBlocking()
@@ -367,15 +361,4 @@ class BackupManager(private val db: DatabaseHelper) {
         }
     }
 
-    /**
-     * Returns a list of items from a json element, or an empty list if the element is null.
-     *
-     * @param element the json to be mapped to a list of items.
-     * @param type the gson mapping to restore the list.
-     * @return a list of items.
-     */
-    private fun <T> getArrayOrEmpty(element: JsonElement?, type: Type): List<T> {
-        return gson.fromJson<List<T>>(element, type) ?: ArrayList<T>()
-    }
-
 }

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

@@ -16,10 +16,7 @@ import eu.kanade.tachiyomi.data.source.Source
 import eu.kanade.tachiyomi.data.source.SourceManager
 import eu.kanade.tachiyomi.data.source.model.Page
 import eu.kanade.tachiyomi.data.source.online.OnlineSource
-import eu.kanade.tachiyomi.util.DiskUtils
-import eu.kanade.tachiyomi.util.DynamicConcurrentMergeOperator
-import eu.kanade.tachiyomi.util.UrlUtil
-import eu.kanade.tachiyomi.util.saveImageTo
+import eu.kanade.tachiyomi.util.*
 import rx.Observable
 import rx.Subscription
 import rx.android.schedulers.AndroidSchedulers
@@ -27,12 +24,17 @@ import rx.schedulers.Schedulers
 import rx.subjects.BehaviorSubject
 import rx.subjects.PublishSubject
 import timber.log.Timber
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
 import java.io.File
 import java.io.FileReader
 import java.util.*
-import java.util.concurrent.TimeUnit
 
-class DownloadManager(private val context: Context, private val sourceManager: SourceManager, private val preferences: PreferencesHelper) {
+class DownloadManager(
+        private val context: Context,
+        private val sourceManager: SourceManager = Injekt.get(),
+        private val preferences: PreferencesHelper = Injekt.get()
+) {
 
     private val gson = Gson()
 
@@ -270,10 +272,8 @@ class DownloadManager(private val context: Context, private val sourceManager: S
                     }
                     page
                 }
-                .retryWhen {
-                    it.zipWith(Observable.range(1, 3)) { errors, retries -> retries }
-                            .flatMap { retries -> Observable.timer((retries * 2).toLong(), TimeUnit.SECONDS) }
-                }
+                // Retry 3 times, waiting 2, 4 and 8 seconds between attempts.
+                .retryWhen(RetryWithDelay(3, { (2 shl it - 1) * 1000 }))
     }
 
     // Public method to get the image from the filesystem. It does NOT provide any way to download the image

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

@@ -7,14 +7,13 @@ import android.os.IBinder
 import android.os.PowerManager
 import com.github.pwittchen.reactivenetwork.library.ConnectivityStatus
 import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.util.toast
 import rx.Subscription
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 class DownloadService : Service() {
 
@@ -29,8 +28,8 @@ class DownloadService : Service() {
         }
     }
 
-    @Inject lateinit var downloadManager: DownloadManager
-    @Inject lateinit var preferences: PreferencesHelper
+    val downloadManager: DownloadManager by injectLazy()
+    val preferences: PreferencesHelper by injectLazy()
 
     private var wakeLock: PowerManager.WakeLock? = null
     private var networkChangeSubscription: Subscription? = null
@@ -39,7 +38,6 @@ class DownloadService : Service() {
 
     override fun onCreate() {
         super.onCreate()
-        App.get(this).component.inject(this)
 
         createWakeLock()
 

+ 5 - 7
app/src/main/java/eu/kanade/tachiyomi/data/glide/AppGlideModule.kt

@@ -7,28 +7,26 @@ import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
 import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory
 import com.bumptech.glide.load.model.GlideUrl
 import com.bumptech.glide.module.GlideModule
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.network.NetworkHelper
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
 import java.io.InputStream
-import javax.inject.Inject
 
 /**
  * Class used to update Glide module settings
  */
 class AppGlideModule : GlideModule {
 
-    @Inject lateinit var networkHelper: NetworkHelper
-
     override fun applyOptions(context: Context, builder: GlideBuilder) {
         // Set the cache size of Glide to 15 MiB
         builder.setDiskCache(InternalCacheDiskCacheFactory(context, 15 * 1024 * 1024))
     }
 
     override fun registerComponents(context: Context, glide: Glide) {
-        App.get(context).component.inject(this)
-        glide.register(GlideUrl::class.java, InputStream::class.java,
-                OkHttpUrlLoader.Factory(networkHelper.client))
+        val networkFactory = OkHttpUrlLoader.Factory(Injekt.get<NetworkHelper>().client)
+
+        glide.register(GlideUrl::class.java, InputStream::class.java, networkFactory)
         glide.register(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory())
     }
 }

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

@@ -5,14 +5,13 @@ import com.bumptech.glide.Glide
 import com.bumptech.glide.load.data.DataFetcher
 import com.bumptech.glide.load.model.*
 import com.bumptech.glide.load.model.stream.StreamModelLoader
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.data.cache.CoverCache
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.source.SourceManager
 import eu.kanade.tachiyomi.data.source.online.OnlineSource
+import uy.kohesive.injekt.injectLazy
 import java.io.File
 import java.io.InputStream
-import javax.inject.Inject
 
 /**
  * A class for loading a cover associated with a [Manga] that can be present in our own cache.
@@ -30,12 +29,12 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> {
     /**
      * Cover cache where persistent covers are stored.
      */
-    @Inject lateinit var coverCache: CoverCache
+    val coverCache: CoverCache by injectLazy()
 
     /**
      * Source manager.
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * Base network loader.
@@ -54,10 +53,6 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> {
      */
     private val cachedHeaders = hashMapOf<Int, LazyHeaders>()
 
-    init {
-        App.get(context).component.inject(this)
-    }
-
     /**
      * Factory class for creating [MangaModelLoader] instances.
      */
@@ -88,7 +83,7 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> {
         // Obtain the request url and the file for this url from the LRU cache, or calculate it
         // and add them to the cache.
         val (glideUrl, file) = modelCache.get(url, width, height) ?:
-            Pair(GlideUrl(url, getHeaders(manga)), coverCache.getCoverFile(url)).apply {
+            Pair(GlideUrl(url, getHeaders(manga)), coverCache.getCoverFile(url!!)).apply {
                 modelCache.put(url, width, height, this)
             }
 

+ 5 - 6
app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt

@@ -10,12 +10,12 @@ import android.os.PowerManager
 import android.support.v4.app.NotificationCompat
 import com.github.pwittchen.reactivenetwork.library.ConnectivityStatus
 import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.Constants
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.data.database.models.Manga
+import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.source.SourceManager
 import eu.kanade.tachiyomi.data.source.online.OnlineSource
@@ -24,9 +24,9 @@ import eu.kanade.tachiyomi.util.*
 import rx.Observable
 import rx.Subscription
 import rx.schedulers.Schedulers
+import uy.kohesive.injekt.injectLazy
 import java.util.*
 import java.util.concurrent.atomic.AtomicInteger
-import javax.inject.Inject
 
 /**
  * This class will take care of updating the chapters of the manga from the library. It can be
@@ -41,17 +41,17 @@ class LibraryUpdateService : Service() {
     /**
      * Database helper.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Source manager.
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * Preferences.
      */
-    @Inject lateinit var preferences: PreferencesHelper
+    val preferences: PreferencesHelper by injectLazy()
 
     /**
      * Wake lock that will be held until the service is destroyed.
@@ -126,7 +126,6 @@ class LibraryUpdateService : Service() {
      */
     override fun onCreate() {
         super.onCreate()
-        App.get(this).component.inject(this)
         createAndAcquireWakeLock()
     }
 

+ 3 - 8
app/src/main/java/eu/kanade/tachiyomi/data/mangasync/MangaSyncService.kt

@@ -2,23 +2,18 @@ package eu.kanade.tachiyomi.data.mangasync
 
 import android.content.Context
 import android.support.annotation.CallSuper
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.data.database.models.MangaSync
 import eu.kanade.tachiyomi.data.network.NetworkHelper
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import okhttp3.OkHttpClient
 import rx.Completable
 import rx.Observable
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 abstract class MangaSyncService(private val context: Context, val id: Int) {
 
-    @Inject lateinit var preferences: PreferencesHelper
-    @Inject lateinit var networkService: NetworkHelper
-
-    init {
-        App.get(context).component.inject(this)
-    }
+    val preferences: PreferencesHelper by injectLazy()
+    val networkService: NetworkHelper by injectLazy()
 
     open val client: OkHttpClient
         get() = networkService.client

+ 3 - 5
app/src/main/java/eu/kanade/tachiyomi/data/mangasync/UpdateMangaSyncService.kt

@@ -4,25 +4,23 @@ import android.app.Service
 import android.content.Context
 import android.content.Intent
 import android.os.IBinder
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.MangaSync
 import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import rx.subscriptions.CompositeSubscription
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 class UpdateMangaSyncService : Service() {
 
-    @Inject lateinit var syncManager: MangaSyncManager
-    @Inject lateinit var db: DatabaseHelper
+    val syncManager: MangaSyncManager by injectLazy()
+    val db: DatabaseHelper by injectLazy()
 
     private lateinit var subscriptions: CompositeSubscription
 
     override fun onCreate() {
         super.onCreate()
-        App.get(this).component.inject(this)
         subscriptions = CompositeSubscription()
     }
 

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/mangasync/myanimelist/MyAnimeList.kt

@@ -97,8 +97,8 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
                 .flatMap { Observable.from(it.select("entry")) }
                 .filter { it.select("type").text() != "Novel" }
                 .map {
-                    MangaSync.create(this).apply {
-                        title = it.selectText("title")
+                    MangaSync.create(id).apply {
+                        title = it.selectText("title")!!
                         remote_id = it.selectInt("id")
                         total_chapters = it.selectInt("chapters")
                     }
@@ -114,8 +114,8 @@ class MyAnimeList(private val context: Context, id: Int) : MangaSyncService(cont
                 .map { Jsoup.parse(it.body().string()) }
                 .flatMap { Observable.from(it.select("manga")) }
                 .map {
-                    MangaSync.create(this).apply {
-                        title = it.selectText("series_title")
+                    MangaSync.create(id).apply {
+                        title = it.selectText("series_title")!!
                         remote_id = it.selectInt("series_mangadb_id")
                         last_chapter_read = it.selectInt("my_read_chapters")
                         status = it.selectInt("my_status")

+ 4 - 10
app/src/main/java/eu/kanade/tachiyomi/data/source/model/Page.java

@@ -1,9 +1,7 @@
 package eu.kanade.tachiyomi.data.source.model;
 
-import java.util.List;
-
-import eu.kanade.tachiyomi.data.database.models.Chapter;
 import eu.kanade.tachiyomi.data.network.ProgressListener;
+import eu.kanade.tachiyomi.ui.reader.ReaderChapter;
 import rx.subjects.PublishSubject;
 
 public class Page implements ProgressListener {
@@ -11,7 +9,7 @@ public class Page implements ProgressListener {
     private int pageNumber;
     private String url;
     private String imageUrl;
-    private transient Chapter chapter;
+    private transient ReaderChapter chapter;
     private transient String imagePath;
     private transient volatile int status;
     private transient volatile int progress;
@@ -90,16 +88,12 @@ public class Page implements ProgressListener {
         this.statusSubject = subject;
     }
 
-    public Chapter getChapter() {
+    public ReaderChapter getChapter() {
         return chapter;
     }
 
-    public void setChapter(Chapter chapter) {
+    public void setChapter(ReaderChapter chapter) {
         this.chapter = chapter;
     }
 
-    public boolean isLastPage() {
-        List<Page> chapterPages = chapter.getPages();
-        return chapterPages.size() -1 == pageNumber;
-    }
 }

+ 14 - 10
app/src/main/java/eu/kanade/tachiyomi/data/source/online/OnlineSource.kt

@@ -1,7 +1,6 @@
 package eu.kanade.tachiyomi.data.source.online
 
 import android.content.Context
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.data.cache.ChapterCache
 import eu.kanade.tachiyomi.data.database.models.Chapter
 import eu.kanade.tachiyomi.data.database.models.Manga
@@ -14,9 +13,10 @@ import eu.kanade.tachiyomi.data.source.Language
 import eu.kanade.tachiyomi.data.source.Source
 import eu.kanade.tachiyomi.data.source.model.MangasPage
 import eu.kanade.tachiyomi.data.source.model.Page
+import eu.kanade.tachiyomi.util.UrlUtil
 import okhttp3.*
 import rx.Observable
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * A simple implementation for sources from a website.
@@ -28,17 +28,17 @@ abstract class OnlineSource(context: Context) : Source {
     /**
      * Network service.
      */
-    @Inject lateinit var network: NetworkHelper
+    val network: NetworkHelper by injectLazy()
 
     /**
      * Chapter cache.
      */
-    @Inject lateinit var chapterCache: ChapterCache
+    val chapterCache: ChapterCache by injectLazy()
 
     /**
      * Preferences helper.
      */
-    @Inject lateinit var preferences: PreferencesHelper
+    val preferences: PreferencesHelper by injectLazy()
 
     /**
      * Base url of the website without the trailing slash, like: http://mysite.com
@@ -61,11 +61,6 @@ abstract class OnlineSource(context: Context) : Source {
     open val client: OkHttpClient
         get() = network.client
 
-    init {
-        // Inject dependencies.
-        App.get(context).component.inject(this)
-    }
-
     /**
      * Headers builder for requests. Implementations can override this method for custom headers.
      */
@@ -443,6 +438,15 @@ abstract class OnlineSource(context: Context) : Source {
         }
     }
 
+    fun Chapter.setUrlWithoutDomain(url: String) {
+        this.url = UrlUtil.getPath(url)
+    }
+
+    fun Manga.setUrlWithoutDomain(url: String) {
+        this.url = UrlUtil.getPath(url)
+    }
+
+
     // Overridable method to allow custom parsing.
     open fun parseChapterNumber(chapter: Chapter) {
 

+ 2 - 4
app/src/main/java/eu/kanade/tachiyomi/data/source/online/ParsedOnlineSource.kt

@@ -26,8 +26,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) {
     override fun popularMangaParse(response: Response, page: MangasPage) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(popularMangaSelector())) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 popularMangaFromElement(element, this)
                 page.mangas.add(this)
             }
@@ -70,8 +69,7 @@ abstract class ParsedOnlineSource(context: Context) : OnlineSource(context) {
     override fun searchMangaParse(response: Response, page: MangasPage, query: String) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(searchMangaSelector())) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 searchMangaFromElement(element, this)
                 page.mangas.add(this)
             }

+ 5 - 7
app/src/main/java/eu/kanade/tachiyomi/data/source/online/YamlOnlineSource.kt

@@ -54,10 +54,9 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
     override fun popularMangaParse(response: Response, page: MangasPage) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(map.popular.manga_css)) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 title = element.text()
-                setUrl(element.attr("href"))
+                setUrlWithoutDomain(element.attr("href"))
                 page.mangas.add(this)
             }
         }
@@ -84,10 +83,9 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
     override fun searchMangaParse(response: Response, page: MangasPage, query: String) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(map.search.manga_css)) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 title = element.text()
-                setUrl(element.attr("href"))
+                setUrlWithoutDomain(element.attr("href"))
                 page.mangas.add(this)
             }
         }
@@ -123,7 +121,7 @@ class YamlOnlineSource(context: Context, mappings: Map<*, *>) : OnlineSource(con
                 val chapter = Chapter.create()
                 element.select(title).first().let {
                     chapter.name = it.text()
-                    chapter.setUrl(it.attr("href"))
+                    chapter.setUrlWithoutDomain(it.attr("href"))
                 }
                 val dateElement = element.select(date?.select).first()
                 chapter.date_upload = date?.getDate(dateElement, pool, dateFormat)?.time ?: 0

+ 4 - 6
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt

@@ -62,8 +62,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
     override fun popularMangaParse(response: Response, page: MangasPage) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(popularMangaSelector())) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 popularMangaFromElement(element, this)
                 page.mangas.add(this)
             }
@@ -78,7 +77,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("a[href^=http://bato.to]").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text().trim()
         }
     }
@@ -90,8 +89,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
     override fun searchMangaParse(response: Response, page: MangasPage, query: String) {
         val document = Jsoup.parse(response.body().string())
         for (element in document.select(searchMangaSelector())) {
-            Manga().apply {
-                source = [email protected]
+            Manga.create(id).apply {
                 searchMangaFromElement(element, this)
                 page.mangas.add(this)
             }
@@ -156,7 +154,7 @@ class Batoto(context: Context, override val id: Int) : ParsedOnlineSource(contex
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a[href^=http://bato.to/reader").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.text()
         chapter.date_upload = element.select("td").getOrNull(4)?.let {
             parseDateFromElement(it)

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Kissmanga.kt

@@ -35,7 +35,7 @@ class Kissmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("td a:eq(0)").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -88,7 +88,7 @@ class Kissmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.text()
         chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
             SimpleDateFormat("MM/dd/yyyy").parse(it).time

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt

@@ -29,7 +29,7 @@ class Mangafox(context: Context, override val id: Int) : ParsedOnlineSource(cont
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("a.title").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -43,7 +43,7 @@ class Mangafox(context: Context, override val id: Int) : ParsedOnlineSource(cont
 
     override fun searchMangaFromElement(element: Element, manga: Manga) {
         element.select("a.series_preview").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -74,7 +74,7 @@ class Mangafox(context: Context, override val id: Int) : ParsedOnlineSource(cont
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a.tips").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.text()
         chapter.date_upload = element.select("span.date").first()?.text()?.let { parseChapterDate(it) } ?: 0
     }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt

@@ -27,7 +27,7 @@ class Mangahere(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("div.title > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -41,7 +41,7 @@ class Mangahere(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun searchMangaFromElement(element: Element, manga: Manga) {
         element.select("a.manga_info").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -71,7 +71,7 @@ class Mangahere(context: Context, override val id: Int) : ParsedOnlineSource(con
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.text()
         chapter.date_upload = element.select("span.right").first()?.text()?.let { parseChapterDate(it) } ?: 0
     }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt

@@ -28,7 +28,7 @@ class Readmangatoday(context: Context, override val id: Int) : ParsedOnlineSourc
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("div.title > h2 > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.attr("title")
         }
     }
@@ -54,7 +54,7 @@ class Readmangatoday(context: Context, override val id: Int) : ParsedOnlineSourc
 
     override fun searchMangaFromElement(element: Element, manga: Manga) {
         element.select("div.title > h2 > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.attr("title")
         }
     }
@@ -83,7 +83,7 @@ class Readmangatoday(context: Context, override val id: Int) : ParsedOnlineSourc
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.select("span.val").text()
         chapter.date_upload = element.select("span.dte").first()?.text()?.let { parseChapterDate(it) } ?: 0
     }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Mangachan.kt

@@ -29,7 +29,7 @@ class Mangachan(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("h2 > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.text()
         }
     }
@@ -69,7 +69,7 @@ class Mangachan(context: Context, override val id: Int) : ParsedOnlineSource(con
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href"))
+        chapter.setUrlWithoutDomain(urlElement.attr("href"))
         chapter.name = urlElement.text()
         chapter.date_upload = element.select("div.date").first()?.text()?.let {
             SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(it).time

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Mintmanga.kt

@@ -30,7 +30,7 @@ class Mintmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("h3 > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.attr("title")
         }
     }
@@ -69,7 +69,7 @@ class Mintmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href") + "?mature=1")
+        chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mature=1")
         chapter.name = urlElement.text().replace(" новое", "")
         chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
             SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/source/online/russian/Readmanga.kt

@@ -30,7 +30,7 @@ class Readmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
 
     override fun popularMangaFromElement(element: Element, manga: Manga) {
         element.select("h3 > a").first().let {
-            manga.setUrl(it.attr("href"))
+            manga.setUrlWithoutDomain(it.attr("href"))
             manga.title = it.attr("title")
         }
     }
@@ -69,7 +69,7 @@ class Readmanga(context: Context, override val id: Int) : ParsedOnlineSource(con
     override fun chapterFromElement(element: Element, chapter: Chapter) {
         val urlElement = element.select("a").first()
 
-        chapter.setUrl(urlElement.attr("href") + "?mature=1")
+        chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mature=1")
         chapter.name = urlElement.text().replace(" новое", "")
         chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
             SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time

+ 2 - 6
app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloader.kt

@@ -8,7 +8,6 @@ import android.content.Intent
 import android.net.Uri
 import android.os.AsyncTask
 import android.support.v4.app.NotificationCompat
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.Constants
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.network.GET
@@ -18,8 +17,8 @@ import eu.kanade.tachiyomi.data.network.newCallWithProgress
 import eu.kanade.tachiyomi.util.notificationManager
 import eu.kanade.tachiyomi.util.saveTo
 import timber.log.Timber
+import uy.kohesive.injekt.injectLazy
 import java.io.File
-import javax.inject.Inject
 
 class UpdateDownloader(private val context: Context) :
         AsyncTask<String, Int, UpdateDownloader.DownloadResult>() {
@@ -40,7 +39,7 @@ class UpdateDownloader(private val context: Context) :
         }
     }
 
-    @Inject lateinit var network: NetworkHelper
+    val network: NetworkHelper by injectLazy()
 
     /**
      * Default download dir
@@ -59,9 +58,6 @@ class UpdateDownloader(private val context: Context) :
     private val notificationId: Int
         get() = Constants.NOTIFICATION_UPDATER_ID
 
-    init {
-        App.get(context).component.inject(this)
-    }
 
     /**
      * Class containing download result

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/backup/BackupPresenter.kt

@@ -8,9 +8,9 @@ import rx.Observable
 import rx.Subscription
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
+import uy.kohesive.injekt.injectLazy
 import java.io.File
 import java.io.InputStream
-import javax.inject.Inject
 
 /**
  * Presenter of [BackupFragment].
@@ -20,7 +20,7 @@ class BackupPresenter : BasePresenter<BackupFragment>() {
     /**
      * Database.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Backup manager.

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt

@@ -12,7 +12,6 @@ abstract class BaseRxActivity<P : BasePresenter<*>> : NucleusAppCompatActivity<P
         setPresenterFactory {
             superFactory.createPresenter().apply {
                 val app = application as App
-                app.componentReflection.inject(this)
                 context = app.applicationContext
             }
         }

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.kt

@@ -12,7 +12,6 @@ abstract class BaseRxFragment<P : BasePresenter<*>> : NucleusSupportFragment<P>(
         setPresenterFactory {
             superFactory.createPresenter().apply {
                 val app = activity.application as App
-                app.componentReflection.inject(this)
                 context = app.applicationContext
             }
         }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt

@@ -56,7 +56,7 @@ class CatalogueAdapter(val fragment: CatalogueFragment) : FlexibleAdapter<Catalo
      * @return an identifier for the item.
      */
     override fun getItemId(position: Int): Long {
-        return mItems[position].id
+        return mItems[position].id!!
     }
 
     /**

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt

@@ -383,7 +383,7 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold
      * @return the holder of the manga or null if it's not bound.
      */
     private fun getHolder(manga: Manga): CatalogueGridHolder? {
-        return catalogue_grid.findViewHolderForItemId(manga.id) as? CatalogueGridHolder
+        return catalogue_grid.findViewHolderForItemId(manga.id!!) as? CatalogueGridHolder
     }
 
     /**

+ 5 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt

@@ -19,7 +19,7 @@ import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import rx.subjects.PublishSubject
 import timber.log.Timber
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Presenter of [CatalogueFragment].
@@ -29,22 +29,22 @@ class CataloguePresenter : BasePresenter<CatalogueFragment>() {
     /**
      * Source manager.
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * Database.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Preferences.
      */
-    @Inject lateinit var prefs: PreferencesHelper
+    val prefs: PreferencesHelper by injectLazy()
 
     /**
      * Cover cache.
      */
-    @Inject lateinit var coverCache: CoverCache
+    val coverCache: CoverCache by injectLazy()
 
     /**
      * Enabled sources.

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryPresenter.kt

@@ -5,7 +5,7 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.Category
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import rx.android.schedulers.AndroidSchedulers
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Presenter of CategoryActivity.
@@ -17,7 +17,7 @@ class CategoryPresenter : BasePresenter<CategoryActivity>() {
     /**
      * Used to connect to database
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * List containing categories

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadAdapter.kt

@@ -35,7 +35,7 @@ class DownloadAdapter(private val context: Context) : FlexibleAdapter<DownloadHo
      * @return an identifier for the item.
      */
     override fun getItemId(position: Int): Long {
-        return getItem(position).chapter.id
+        return getItem(position).chapter.id!!
     }
 
     /**

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadFragment.kt

@@ -262,7 +262,7 @@ class DownloadFragment : BaseRxFragment<DownloadPresenter>() {
      * @return the holder of the download or null if it's not bound.
      */
     private fun getHolder(download: Download): DownloadHolder? {
-        return recycler.findViewHolderForItemId(download.chapter.id) as? DownloadHolder
+        return recycler.findViewHolderForItemId(download.chapter.id!!) as? DownloadHolder
     }
 
     /**

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadPresenter.kt

@@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.data.download.model.DownloadQueue
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import rx.Observable
 import timber.log.Timber
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Presenter of [DownloadFragment].
@@ -24,7 +24,7 @@ class DownloadPresenter : BasePresenter<DownloadFragment>() {
     /**
      * Download manager.
      */
-    @Inject lateinit var downloadManager: DownloadManager
+    val downloadManager: DownloadManager by injectLazy()
 
     /**
      * Property to get the queue from the download manager.

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryCategoryAdapter.kt

@@ -49,7 +49,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
      * @return an identifier for the item.
      */
     override fun getItemId(position: Int): Long {
-        return mItems[position].id
+        return mItems[position].id!!
     }
 
     /**
@@ -72,8 +72,8 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryFragment) :
      * @return true if the manga should be included, false otherwise.
      */
     override fun filterObject(manga: Manga, query: String): Boolean = with(manga) {
-        title != null && title.toLowerCase().contains(query) ||
-                author != null && author.toLowerCase().contains(query)
+        title.toLowerCase().contains(query) ||
+                author != null && author!!.toLowerCase().contains(query)
     }
 
     /**

+ 7 - 7
app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt

@@ -16,10 +16,10 @@ import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import rx.subjects.BehaviorSubject
+import uy.kohesive.injekt.injectLazy
 import java.io.IOException
 import java.io.InputStream
 import java.util.*
-import javax.inject.Inject
 
 /**
  * Presenter of [LibraryFragment].
@@ -49,27 +49,27 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
     /**
      * Database.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Preferences.
      */
-    @Inject lateinit var preferences: PreferencesHelper
+    val preferences: PreferencesHelper by injectLazy()
 
     /**
      * Cover cache.
      */
-    @Inject lateinit var coverCache: CoverCache
+    val coverCache: CoverCache by injectLazy()
 
     /**
      * Source manager.
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * Download manager.
      */
-    @Inject lateinit var downloadManager: DownloadManager
+    val downloadManager: DownloadManager by injectLazy()
 
     companion object {
         /**
@@ -279,7 +279,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
     @Throws(IOException::class)
     fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean {
         if (manga.thumbnail_url != null && manga.favorite) {
-            coverCache.copyToCache(manga.thumbnail_url, inputStream)
+            coverCache.copyToCache(manga.thumbnail_url!!, inputStream)
             return true
         }
         return false

+ 2 - 5
app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt

@@ -5,7 +5,6 @@ import android.os.Bundle
 import android.support.v4.app.Fragment
 import android.support.v4.view.GravityCompat
 import android.view.MenuItem
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.ui.backup.BackupFragment
@@ -18,11 +17,11 @@ import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadFragment
 import eu.kanade.tachiyomi.ui.setting.SettingsActivity
 import kotlinx.android.synthetic.main.activity_main.*
 import kotlinx.android.synthetic.main.toolbar.*
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 class MainActivity : BaseActivity() {
 
-    @Inject lateinit var preferences: PreferencesHelper
+    val preferences: PreferencesHelper by injectLazy()
 
     override fun onCreate(savedState: Bundle?) {
         setAppTheme()
@@ -34,8 +33,6 @@ class MainActivity : BaseActivity() {
             return
         }
 
-        App.get(this).component.inject(this)
-
         // Inflate activity_main.xml.
         setContentView(R.layout.activity_main)
 

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.ui.manga.info.ChapterCountEvent
 import eu.kanade.tachiyomi.util.SharedData
 import rx.Observable
 import rx.Subscription
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Presenter of [MangaActivity].
@@ -19,12 +19,12 @@ class MangaPresenter : BasePresenter<MangaActivity>() {
     /**
      * Database helper.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Manga sync manager.
      */
-    @Inject lateinit var syncManager: MangaSyncManager
+    val syncManager: MangaSyncManager by injectLazy()
 
     /**
      * Manga associated with this instance.

+ 19 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterModel.kt

@@ -0,0 +1,19 @@
+package eu.kanade.tachiyomi.ui.manga.chapter
+
+import eu.kanade.tachiyomi.data.database.models.Chapter
+import eu.kanade.tachiyomi.data.download.model.Download
+
+class ChapterModel(c: Chapter) : Chapter by c {
+
+    private var _status: Int = 0
+
+    var status: Int
+        get() = download?.status ?: _status
+        set(value) { _status = value }
+
+    var download: Download? = null
+
+    val isDownloaded: Boolean
+        get() = status == Download.DOWNLOADED
+
+}

+ 3 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersAdapter.kt

@@ -3,10 +3,9 @@ package eu.kanade.tachiyomi.ui.manga.chapter
 import android.view.ViewGroup
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.Chapter
 import eu.kanade.tachiyomi.util.inflate
 
-class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChaptersHolder, Chapter>() {
+class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<ChaptersHolder, ChapterModel>() {
 
     init {
         setHasStableIds(true)
@@ -30,10 +29,10 @@ class ChaptersAdapter(val fragment: ChaptersFragment) : FlexibleAdapter<Chapters
     }
 
     override fun getItemId(position: Int): Long {
-        return mItems[position].id
+        return mItems[position].id!!
     }
 
-    fun setItems(chapters: List<Chapter>) {
+    fun setItems(chapters: List<ChapterModel>) {
         mItems = chapters
         notifyDataSetChanged()
     }

+ 11 - 12
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersFragment.kt

@@ -134,8 +134,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
                 presenter.setDownloadedFilter(item.isChecked)
             }
             R.id.action_filter_empty -> {
-                presenter.setReadFilter(false)
-                presenter.setDownloadedFilter(false)
+                presenter.removeFilters()
                 activity.supportInvalidateOptionsMenu()
             }
             R.id.action_sort -> presenter.revertSortOrder()
@@ -150,7 +149,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
         setDownloadedFilter()
     }
 
-    fun onNextChapters(chapters: List<Chapter>) {
+    fun onNextChapters(chapters: List<ChapterModel>) {
         // If the list is empty, fetch chapters from source if the conditions are met
         // We use presenter chapters instead because they are always unfiltered
         if (presenter.chapters.isEmpty())
@@ -206,7 +205,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
                     // Save the new display mode
                     presenter.setDisplayMode(itemView.id)
                     // Refresh ui
-                    adapter.notifyDataSetChanged()
+                    adapter.notifyItemRangeChanged(0, adapter.itemCount)
                     true
                 }
                 .show()
@@ -271,7 +270,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
     }
 
     private fun getHolder(chapter: Chapter): ChaptersHolder? {
-        return recycler.findViewHolderForItemId(chapter.id) as? ChaptersHolder
+        return recycler.findViewHolderForItemId(chapter.id!!) as? ChaptersHolder
     }
 
     override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
@@ -309,7 +308,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
         actionMode = null
     }
 
-    fun getSelectedChapters(): List<Chapter> {
+    fun getSelectedChapters(): List<ChapterModel> {
         return adapter.selectedItems.map { adapter.getItem(it) }
     }
 
@@ -322,27 +321,27 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
         setContextTitle(adapter.selectedItemCount)
     }
 
-    fun markAsRead(chapters: List<Chapter>) {
+    fun markAsRead(chapters: List<ChapterModel>) {
         presenter.markChaptersRead(chapters, true)
         if (presenter.preferences.removeAfterMarkedAsRead()) {
             deleteChapters(chapters)
         }
     }
 
-    fun markAsUnread(chapters: List<Chapter>) {
+    fun markAsUnread(chapters: List<ChapterModel>) {
         presenter.markChaptersRead(chapters, false)
     }
 
-    fun markPreviousAsRead(chapter: Chapter) {
+    fun markPreviousAsRead(chapter: ChapterModel) {
         presenter.markPreviousChaptersAsRead(chapter)
     }
 
-    fun downloadChapters(chapters: List<Chapter>) {
+    fun downloadChapters(chapters: List<ChapterModel>) {
         destroyActionModeIfNeeded()
         presenter.downloadChapters(chapters)
     }
 
-    fun deleteChapters(chapters: List<Chapter>) {
+    fun deleteChapters(chapters: List<ChapterModel>) {
         destroyActionModeIfNeeded()
         DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
         presenter.deleteChapters(chapters)
@@ -350,7 +349,7 @@ class ChaptersFragment : BaseRxFragment<ChaptersPresenter>(), ActionMode.Callbac
 
     fun onChaptersDeleted() {
         dismissDeletingDialog()
-        adapter.notifyDataSetChanged()
+        adapter.notifyItemRangeChanged(0, adapter.itemCount)
     }
 
     fun onChaptersDeletedError(error: Throwable) {

+ 29 - 36
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersHolder.kt

@@ -1,10 +1,8 @@
 package eu.kanade.tachiyomi.ui.manga.chapter
 
-import android.content.Context
 import android.view.View
 import android.widget.PopupMenu
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.Chapter
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
@@ -26,7 +24,7 @@ class ChaptersHolder(
     private val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols().apply { decimalSeparator = '.' })
     private val df = DateFormat.getDateInstance(DateFormat.SHORT)
 
-    private var item: Chapter? = null
+    private var item: ChapterModel? = null
 
     init {
         // We need to post a Runnable to show the popup to make sure that the PopupMenu is
@@ -35,19 +33,16 @@ class ChaptersHolder(
         view.chapter_menu.setOnClickListener { it.post { showPopupMenu(it) } }
     }
 
-    fun onSetValues(chapter: Chapter, manga: Manga?) = with(view) {
+    fun onSetValues(chapter: ChapterModel, manga: Manga?) = with(view) {
         item = chapter
 
-        val name: String
-        when (manga?.displayMode) {
+        chapter_title.text = when (manga?.displayMode) {
             Manga.DISPLAY_NUMBER -> {
                 val formattedNumber = decimalFormat.format(chapter.chapter_number.toDouble())
-                name = context.getString(R.string.display_mode_chapter, formattedNumber)
+                context.getString(R.string.display_mode_chapter, formattedNumber)
             }
-            else -> name = chapter.name
+            else -> chapter.name
         }
-
-        chapter_title.text = name
         chapter_title.setTextColor(if (chapter.read) readColor else unreadColor)
 
         if (chapter.date_upload > 0) {
@@ -57,31 +52,26 @@ class ChaptersHolder(
             chapter_date.text = ""
         }
 
-        if (!chapter.read && chapter.last_page_read > 0) {
-            chapter_pages.text = context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
+        chapter_pages.text = if (!chapter.read && chapter.last_page_read > 0) {
+            context.getString(R.string.chapter_progress, chapter.last_page_read + 1)
         } else {
-            chapter_pages.text = ""
+            ""
         }
 
         notifyStatus(chapter.status)
     }
 
-    fun notifyStatus(status: Int) = with(view) {
+    fun notifyStatus(status: Int) = with(view.download_text) {
         when (status) {
-            Download.QUEUE -> download_text.setText(R.string.chapter_queued)
-            Download.DOWNLOADING -> download_text.setText(R.string.chapter_downloading)
-            Download.DOWNLOADED -> download_text.setText(R.string.chapter_downloaded)
-            Download.ERROR -> download_text.setText(R.string.chapter_error)
-            else -> download_text.text = ""
+            Download.QUEUE -> setText(R.string.chapter_queued)
+            Download.DOWNLOADING -> setText(R.string.chapter_downloading)
+            Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
+            Download.ERROR -> setText(R.string.chapter_error)
+            else -> text = ""
         }
     }
 
-    fun onProgressChange(context: Context, downloaded: Int, total: Int) {
-        view.download_text.text = context.getString(
-                R.string.chapter_downloading_progress, downloaded, total)
-    }
-
-    private fun showPopupMenu(view: View) = item?.let { item ->
+    private fun showPopupMenu(view: View) = item?.let { chapter ->
         // Create a PopupMenu, giving it the clicked view for an anchor
         val popup = PopupMenu(view.context, view)
 
@@ -89,32 +79,35 @@ class ChaptersHolder(
         popup.menuInflater.inflate(R.menu.chapter_single, popup.menu)
 
         // Hide download and show delete if the chapter is downloaded
-        if (item.isDownloaded) {
+        if (chapter.isDownloaded) {
             popup.menu.findItem(R.id.action_download).isVisible = false
             popup.menu.findItem(R.id.action_delete).isVisible = true
         }
 
         // Hide mark as unread when the chapter is unread
-        if (!item.read && item.last_page_read == 0) {
+        if (!chapter.read && chapter.last_page_read == 0) {
             popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
         }
 
         // Hide mark as read when the chapter is read
-        if (item.read) {
+        if (chapter.read) {
             popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
         }
 
         // Set a listener so we are notified if a menu item is clicked
         popup.setOnMenuItemClickListener { menuItem ->
-            val chapter = listOf(item)
-
-            when (menuItem.itemId) {
-                R.id.action_download -> adapter.fragment.downloadChapters(chapter)
-                R.id.action_delete -> adapter.fragment.deleteChapters(chapter)
-                R.id.action_mark_as_read -> adapter.fragment.markAsRead(chapter)
-                R.id.action_mark_as_unread -> adapter.fragment.markAsUnread(chapter)
-                R.id.action_mark_previous_as_read -> adapter.fragment.markPreviousAsRead(item)
+            val chapterList = listOf(chapter)
+
+            with(adapter.fragment) {
+                when (menuItem.itemId) {
+                    R.id.action_download -> downloadChapters(chapterList)
+                    R.id.action_delete -> deleteChapters(chapterList)
+                    R.id.action_mark_as_read -> markAsRead(chapterList)
+                    R.id.action_mark_as_unread -> markAsUnread(chapterList)
+                    R.id.action_mark_previous_as_read -> markPreviousAsRead(chapter)
+                }
             }
+
             true
         }
 

+ 230 - 75
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersPresenter.kt

@@ -20,108 +20,197 @@ import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import rx.subjects.PublishSubject
 import timber.log.Timber
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
+/**
+ * Presenter of [ChaptersFragment].
+ */
 class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
 
-    @Inject lateinit var db: DatabaseHelper
-    @Inject lateinit var sourceManager: SourceManager
-    @Inject lateinit var preferences: PreferencesHelper
-    @Inject lateinit var downloadManager: DownloadManager
-
+    /**
+     * Database helper.
+     */
+    val db: DatabaseHelper by injectLazy()
+
+    /**
+     * Source manager.
+     */
+    val sourceManager: SourceManager by injectLazy()
+
+    /**
+     * Preferences.
+     */
+    val preferences: PreferencesHelper by injectLazy()
+
+    /**
+     * Downloads manager.
+     */
+    val downloadManager: DownloadManager by injectLazy()
+
+    /**
+     * Active manga.
+     */
     lateinit var manga: Manga
         private set
 
+    /**
+     * Source of the manga.
+     */
     lateinit var source: Source
         private set
 
-    lateinit var chapters: List<Chapter>
+    /**
+     * List of chapters of the manga. It's always unfiltered and unsorted.
+     */
+    lateinit var chapters: List<ChapterModel>
         private set
 
-    lateinit var chaptersSubject: PublishSubject<List<Chapter>>
-        private set
+    /**
+     * Subject of list of chapters to allow updating the view without going to DB.
+     */
+    val chaptersSubject by lazy { PublishSubject.create<List<ChapterModel>>() }
 
-    var hasRequested: Boolean = false
+    /**
+     * Whether the chapter list has been requested to the source.
+     */
+    var hasRequested = false
         private set
 
-    private val DB_CHAPTERS = 1
-    private val FETCH_CHAPTERS = 2
-    private val CHAPTER_STATUS_CHANGES = 3
+    companion object {
+        /**
+         * Id of the restartable which sends a filtered and ordered list of chapters to the view.
+         */
+        private const val GET_CHAPTERS = 1
+
+        /**
+         * Id of the restartable which requests an updated list of chapters to the source.
+         */
+        private const val FETCH_CHAPTERS = 2
+
+        /**
+         * Id of the restartable which listens for download status changes.
+         */
+        private const val CHAPTER_STATUS_CHANGES = 3
+    }
 
     override fun onCreate(savedState: Bundle?) {
         super.onCreate(savedState)
 
-        chaptersSubject = PublishSubject.create()
-
-        startableLatestCache(DB_CHAPTERS,
-                { getDbChaptersObs() },
+        startableLatestCache(GET_CHAPTERS,
+                // On each subject emission, apply filters and sort then update the view.
+                { chaptersSubject
+                        .flatMap { applyChapterFilters(it) }
+                        .observeOn(AndroidSchedulers.mainThread()) },
                 { view, chapters -> view.onNextChapters(chapters) })
 
         startableFirst(FETCH_CHAPTERS,
-                { getOnlineChaptersObs() },
+                { getRemoteChaptersObservable() },
                 { view, result -> view.onFetchChaptersDone() },
                 { view, error -> view.onFetchChaptersError(error) })
 
         startableLatestCache(CHAPTER_STATUS_CHANGES,
-                { getChapterStatusObs() },
+                { getChapterStatusObservable() },
                 { view, download -> view.onChapterStatusChange(download) },
                 { view, error -> Timber.e(error.cause, error.message) })
 
+        // Find the active manga from the shared data or return.
         manga = SharedData.get(MangaEvent::class.java)?.manga ?: return
         Observable.just(manga)
                 .subscribeLatestCache({ view, manga -> view.onNextManga(manga) })
 
+        // Find the source for this manga.
         source = sourceManager.get(manga.source)!!
-        start(DB_CHAPTERS)
 
+        // Prepare the publish subject.
+        start(GET_CHAPTERS)
+
+        // Add the subscription that retrieves the chapters from the database, keeps subscribed to
+        // changes, and sends the list of chapters to the publish subject.
         add(db.getChapters(manga).asRxObservable()
+                .map { chapters ->
+                    // Convert every chapter to a model.
+                    chapters.map { it.toModel() }
+                }
                 .doOnNext { chapters ->
+                    // Store the last emission
                     this.chapters = chapters
-                    SharedData.get(ChapterCountEvent::class.java)?.emit(chapters.size)
-                    for (chapter in chapters) {
-                        setChapterStatus(chapter)
-                    }
+
+                    // Listen for download status changes
                     start(CHAPTER_STATUS_CHANGES)
+
+                    // Emit the number of chapters to the info tab.
+                    SharedData.get(ChapterCountEvent::class.java)?.emit(chapters.size)
                 }
                 .subscribe { chaptersSubject.onNext(it) })
     }
 
+    /**
+     * Converts a chapter from the database to an extended model, allowing to store new fields.
+     */
+    private fun Chapter.toModel(): ChapterModel {
+        // Create the model object.
+        val model = ChapterModel(this)
+
+        // Find an active download for this chapter.
+        val download = downloadManager.queue.find { it.chapter.id == id }
+
+        if (download != null) {
+            // If there's an active download, assign it.
+            model.download = download
+        } else {
+            // Otherwise ask the manager if the chapter is downloaded and assign it to the status.
+            model.status = if (downloadManager.isChapterDownloaded(source, manga, this))
+                Download.DOWNLOADED
+            else
+                Download.NOT_DOWNLOADED
+        }
+        return model
+    }
+
+    /**
+     * Requests an updated list of chapters from the source.
+     */
     fun fetchChaptersFromSource() {
         hasRequested = true
         start(FETCH_CHAPTERS)
     }
 
+    /**
+     * Updates the UI after applying the filters.
+     */
     private fun refreshChapters() {
         chaptersSubject.onNext(chapters)
     }
 
-    fun getOnlineChaptersObs(): Observable<Pair<Int, Int>> {
-        return source.fetchChapterList(manga)
-                .subscribeOn(Schedulers.io())
-                .map { syncChaptersWithSource(db, it, manga, source) }
-                .observeOn(AndroidSchedulers.mainThread())
-    }
-
-    fun getDbChaptersObs(): Observable<List<Chapter>> {
-        return chaptersSubject
-                .flatMap { applyChapterFilters(it) }
-                .observeOn(AndroidSchedulers.mainThread())
-    }
-
-    fun getChapterStatusObs(): Observable<Download> {
-        return downloadManager.queue.getStatusObservable()
-                .observeOn(AndroidSchedulers.mainThread())
-                .filter { download -> download.manga.id == manga.id }
-                .doOnNext { updateChapterStatus(it) }
-    }
-
-    private fun applyChapterFilters(chapters: List<Chapter>): Observable<List<Chapter>> {
+    /**
+     * Returns an observable that updates the chapter list with the latest from the source.
+     */
+    fun getRemoteChaptersObservable() = source.fetchChapterList(manga)
+            .subscribeOn(Schedulers.io())
+            .map { syncChaptersWithSource(db, it, manga, source) }
+            .observeOn(AndroidSchedulers.mainThread())
+
+    /**
+     * Returns an observable that listens to download queue status changes.
+     */
+    fun getChapterStatusObservable() = downloadManager.queue.getStatusObservable()
+            .observeOn(AndroidSchedulers.mainThread())
+            .filter { download -> download.manga.id == manga.id }
+            .doOnNext { onDownloadStatusChange(it) }
+
+    /**
+     * Applies the view filters to the list of chapters obtained from the database.
+     *
+     * @param chapters the list of chapters from the database
+     * @return an observable of the list of chapters filtered and sorted.
+     */
+    private fun applyChapterFilters(chapters: List<ChapterModel>): Observable<List<ChapterModel>> {
         var observable = Observable.from(chapters).subscribeOn(Schedulers.io())
         if (onlyUnread()) {
-            observable = observable.filter { chapter -> !chapter.read }
+            observable = observable.filter { !it.read }
         }
         if (onlyDownloaded()) {
-            observable = observable.filter { chapter -> chapter.status == Download.DOWNLOADED }
+            observable = observable.filter { it.isDownloaded }
         }
         val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
             Manga.SORTING_SOURCE -> when (sortDescending()) {
@@ -137,37 +226,40 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
         return observable.toSortedList(sortFunction)
     }
 
-    private fun setChapterStatus(chapter: Chapter) {
-        for (download in downloadManager.queue) {
-            if (chapter.id == download.chapter.id) {
-                chapter.status = download.status
-                return
+    /**
+     * Called when a download for the active manga changes status.
+     *
+     * @param download the download whose status changed.
+     */
+    fun onDownloadStatusChange(download: Download) {
+        // Assign the download to the model object.
+        if (download.status == Download.QUEUE) {
+            chapters.find { it.id == download.chapter.id }?.let {
+                if (it.download == null) {
+                    it.download = download
+                }
             }
         }
 
-        if (downloadManager.isChapterDownloaded(source, manga, chapter)) {
-            chapter.status = Download.DOWNLOADED
-        } else {
-            chapter.status = Download.NOT_DOWNLOADED
-        }
-    }
-
-    fun updateChapterStatus(download: Download) {
-        for (chapter in chapters) {
-            if (download.chapter.id == chapter.id) {
-                chapter.status = download.status
-                break
-            }
-        }
+        // Force UI update if downloaded filter active and download finished.
         if (onlyDownloaded() && download.status == Download.DOWNLOADED)
             refreshChapters()
     }
 
-    fun getNextUnreadChapter(): Chapter? {
+    /**
+     * Returns the next unread chapter or null if everything is read.
+     */
+    fun getNextUnreadChapter(): ChapterModel? {
         return chapters.sortedByDescending { it.source_order }.find { !it.read }
     }
 
-    fun markChaptersRead(selectedChapters: List<Chapter>, read: Boolean) {
+    /**
+     * Mark the selected chapter list as read/unread.
+     *
+     * @param selectedChapters the list of selected chapters.
+     * @param read whether to mark chapters as read or unread.
+     */
+    fun markChaptersRead(selectedChapters: List<ChapterModel>, read: Boolean) {
         Observable.from(selectedChapters)
                 .doOnNext { chapter ->
                     chapter.read = read
@@ -181,21 +273,36 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
                 .subscribe()
     }
 
-    fun markPreviousChaptersAsRead(selected: Chapter) {
+    /**
+     * Mark the previous chapters to the selected one as read.
+     *
+     * @param chapter the selected chapter.
+     */
+    fun markPreviousChaptersAsRead(chapter: ChapterModel) {
         Observable.from(chapters)
-                .filter { it.isRecognizedNumber && it.chapter_number < selected.chapter_number }
+                .filter { it.isRecognizedNumber && it.chapter_number < chapter.chapter_number }
                 .doOnNext { it.read = true }
                 .toList()
                 .flatMap { db.updateChaptersProgress(it).asRxObservable() }
                 .subscribe()
     }
 
-    fun downloadChapters(chapters: List<Chapter>) {
+    /**
+     * Downloads the given list of chapters with the manager.
+     *
+     * @param chapters the list of chapters to download.
+     */
+    fun downloadChapters(chapters: List<ChapterModel>) {
         DownloadService.start(context)
         downloadManager.downloadChapters(manga, chapters)
     }
 
-    fun deleteChapters(chapters: List<Chapter>) {
+    /**
+     * Deletes the given list of chapter.
+     *
+     * @param chapters the list of chapters to delete.
+     */
+    fun deleteChapters(chapters: List<ChapterModel>) {
         val wasRunning = downloadManager.isRunning
         if (wasRunning) {
             DownloadService.stop(context)
@@ -216,49 +323,97 @@ class ChaptersPresenter : BasePresenter<ChaptersFragment>() {
                 })
     }
 
-    private fun deleteChapter(chapter: Chapter) {
+    /**
+     * Deletes a chapter from disk. This method is called in a background thread.
+     *
+     * @param chapter the chapter to delete.
+     */
+    private fun deleteChapter(chapter: ChapterModel) {
         downloadManager.queue.del(chapter)
         downloadManager.deleteChapter(source, manga, chapter)
         chapter.status = Download.NOT_DOWNLOADED
+        chapter.download = null
     }
 
+    /**
+     * Reverses the sorting and requests an UI update.
+     */
     fun revertSortOrder() {
         manga.setChapterOrder(if (sortDescending()) Manga.SORT_ASC else Manga.SORT_DESC)
         db.updateFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
+    /**
+     * Sets the read filter and requests an UI update.
+     *
+     * @param onlyUnread whether to display only unread chapters or all chapters.
+     */
     fun setReadFilter(onlyUnread: Boolean) {
         manga.readFilter = if (onlyUnread) Manga.SHOW_UNREAD else Manga.SHOW_ALL
         db.updateFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
+    /**
+     * Sets the download filter and requests an UI update.
+     *
+     * @param onlyDownloaded whether to display only downloaded chapters or all chapters.
+     */
     fun setDownloadedFilter(onlyDownloaded: Boolean) {
         manga.downloadedFilter = if (onlyDownloaded) Manga.SHOW_DOWNLOADED else Manga.SHOW_ALL
         db.updateFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
+    /**
+     * Removes all filters and requests an UI update.
+     */
+    fun removeFilters() {
+        manga.readFilter = Manga.SHOW_ALL
+        manga.downloadedFilter = Manga.SHOW_ALL
+        db.updateFlags(manga).executeAsBlocking()
+        refreshChapters()
+    }
+
+    /**
+     * Sets the active display mode.
+     *
+     * @param mode the mode to set.
+     */
     fun setDisplayMode(mode: Int) {
         manga.displayMode = mode
         db.updateFlags(manga).executeAsBlocking()
     }
 
-    fun setSorting(mode: Int) {
-        manga.sorting = mode
+    /**
+     * Sets the sorting method and requests an UI update.
+     *
+     * @param sort the sorting mode.
+     */
+    fun setSorting(sort: Int) {
+        manga.sorting = sort
         db.updateFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
+    /**
+     * Whether the display only downloaded filter is enabled.
+     */
     fun onlyDownloaded(): Boolean {
         return manga.downloadedFilter == Manga.SHOW_DOWNLOADED
     }
 
+    /**
+     * Whether the display only unread filter is enabled.
+     */
     fun onlyUnread(): Boolean {
         return manga.readFilter == Manga.SHOW_UNREAD
     }
 
+    /**
+     * Whether the sorting method is descending or ascending.
+     */
     fun sortDescending(): Boolean {
         return manga.sortDescending()
     }

+ 6 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt

@@ -104,7 +104,12 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
         manga_genres.text = manga.genre
 
         // Update status TextView.
-        manga_status.text = manga.getStatus(activity)
+        manga_status.setText(when (manga.status) {
+            Manga.ONGOING -> R.string.ongoing
+            Manga.COMPLETED -> R.string.completed
+            Manga.LICENSED -> R.string.licensed
+            else -> R.string.unknown
+        })
 
         // Update description TextView.
         manga_summary.text = manga.description

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt

@@ -12,7 +12,7 @@ import eu.kanade.tachiyomi.util.SharedData
 import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Presenter of MangaInfoFragment.
@@ -36,17 +36,17 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
     /**
      * Used to connect to database.
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Used to connect to different manga sources.
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * Used to connect to cache.
      */
-    @Inject lateinit var coverCache: CoverCache
+    val coverCache: CoverCache by injectLazy()
 
     /**
      * The id of the restartable.

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListPresenter.kt

@@ -15,12 +15,12 @@ import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import timber.log.Timber
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 class MyAnimeListPresenter : BasePresenter<MyAnimeListFragment>() {
 
-    @Inject lateinit var db: DatabaseHelper
-    @Inject lateinit var syncManager: MangaSyncManager
+    val db: DatabaseHelper by injectLazy()
+    val syncManager: MangaSyncManager by injectLazy()
 
     val myAnimeList by lazy { syncManager.myAnimeList }
 
@@ -124,7 +124,7 @@ class MyAnimeListPresenter : BasePresenter<MyAnimeListFragment>() {
 
     fun registerManga(sync: MangaSync?) {
         if (sync != null) {
-            sync.manga_id = manga.id
+            sync.manga_id = manga.id!!
             add(myAnimeList.bind(sync)
                     .flatMap { db.insertMangaSync(sync).asRxObservable() }
                     .subscribeOn(Schedulers.io())

+ 22 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapter.kt

@@ -0,0 +1,22 @@
+package eu.kanade.tachiyomi.ui.recent_updates
+
+import eu.kanade.tachiyomi.data.database.models.Chapter
+import eu.kanade.tachiyomi.data.database.models.MangaChapter
+import eu.kanade.tachiyomi.data.download.model.Download
+
+class RecentChapter(mc: MangaChapter) : Chapter by mc.chapter {
+
+    val manga = mc.manga
+
+    private var _status: Int = 0
+
+    var status: Int
+        get() = download?.status ?: _status
+        set(value) { _status = value }
+
+    var download: Download? = null
+
+    val isDownloaded: Boolean
+        get() = status == Download.DOWNLOADED
+
+}

+ 6 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersAdapter.kt

@@ -5,7 +5,6 @@ import android.view.View
 import android.view.ViewGroup
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.MangaChapter
 import eu.kanade.tachiyomi.util.inflate
 import java.util.*
 
@@ -18,7 +17,8 @@ import java.util.*
  * @constructor creates an instance of the adapter.
  */
 
-class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdapter<RecyclerView.ViewHolder, Any>() {
+class RecentChaptersAdapter(val fragment: RecentChaptersFragment)
+: FlexibleAdapter<RecyclerView.ViewHolder, Any>() {
     /**
      * The id of the view type
      */
@@ -45,7 +45,7 @@ class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdap
         val item = getItem(position)
         when (holder.itemViewType) {
             VIEW_TYPE_CHAPTER -> {
-                if (item is MangaChapter) {
+                if (item is RecentChapter) {
                     (holder as RecentChaptersHolder).onSetValues(item)
                 }
             }
@@ -89,7 +89,7 @@ class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdap
      * @param position position of item
      */
     override fun getItemViewType(position: Int): Int {
-        return if (getItem(position) is MangaChapter) VIEW_TYPE_CHAPTER else VIEW_TYPE_SECTION
+        return if (getItem(position) is RecentChapter) VIEW_TYPE_CHAPTER else VIEW_TYPE_SECTION
     }
 
 
@@ -110,8 +110,8 @@ class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdap
      */
     override fun getItemId(position: Int): Long {
         val item = getItem(position)
-        if (item is MangaChapter)
-            return item.chapter.id
+        if (item is RecentChapter)
+            return item.id!!
         else
             return item.hashCode().toLong()
     }

+ 82 - 83
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersFragment.kt

@@ -7,14 +7,12 @@ import android.view.*
 import com.afollestad.materialdialogs.MaterialDialog
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.MangaChapter
 import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
 import eu.kanade.tachiyomi.ui.main.MainActivity
 import eu.kanade.tachiyomi.ui.reader.ReaderActivity
 import eu.kanade.tachiyomi.util.getResourceDrawable
-import eu.kanade.tachiyomi.util.toast
 import eu.kanade.tachiyomi.widget.DeletingChaptersDialog
 import eu.kanade.tachiyomi.widget.DividerItemDecoration
 import eu.kanade.tachiyomi.widget.NpaLinearLayoutManager
@@ -28,7 +26,9 @@ import timber.log.Timber
  * UI related actions should be called from here.
  */
 @RequiresPresenter(RecentChaptersPresenter::class)
-class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
+class RecentChaptersFragment
+: BaseRxFragment<RecentChaptersPresenter>(), ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {
+
     companion object {
         /**
          * Create new RecentChaptersFragment.
@@ -40,54 +40,6 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
         }
     }
 
-    override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
-        return false
-    }
-
-    /**
-     * Called when ActionMode item clicked
-     * @param mode the ActionMode object
-     * @param item item from ActionMode.
-     */
-    override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
-        when (item.itemId) {
-            R.id.action_mark_as_read -> markAsRead(getSelectedChapters())
-            R.id.action_mark_as_unread -> markAsUnread(getSelectedChapters())
-            R.id.action_download -> downloadChapters(getSelectedChapters())
-            R.id.action_delete -> {
-                MaterialDialog.Builder(activity)
-                        .content(R.string.confirm_delete_chapters)
-                        .positiveText(android.R.string.yes)
-                        .negativeText(android.R.string.no)
-                        .onPositive { dialog, action -> deleteChapters(getSelectedChapters()) }
-                        .show()
-            }
-            else -> return false
-        }
-        return true
-    }
-
-    /**
-     * Called when ActionMode created.
-     * @param mode the ActionMode object
-     * @param menu menu object of ActionMode
-     */
-    override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
-        mode.menuInflater.inflate(R.menu.chapter_recent_selection, menu)
-        adapter.mode = FlexibleAdapter.MODE_MULTI
-        return true
-    }
-
-    /**
-     * Called when ActionMode destroyed
-     * @param mode the ActionMode object
-     */
-    override fun onDestroyActionMode(mode: ActionMode?) {
-        adapter.mode = FlexibleAdapter.MODE_SINGLE
-        adapter.clearSelection()
-        actionMode = null
-    }
-
     /**
      * Action mode for multiple selection.
      */
@@ -105,7 +57,7 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
      * @param container view group
      * @param savedState status of saved state
      */
-    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View? {
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View {
         // Inflate view
         return inflater.inflate(R.layout.fragment_recent_chapters, container, false)
     }
@@ -115,7 +67,7 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
      * @param view created view
      * @param savedInstanceState status of saved sate
      */
-    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
         // Init RecyclerView and adapter
         recycler.layoutManager = NpaLinearLayoutManager(activity)
         recycler.addItemDecoration(DividerItemDecoration(context.theme.getResourceDrawable(R.attr.divider_drawable)))
@@ -129,10 +81,10 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
 
     /**
      * Returns selected chapters
-     * @return list of [MangaChapter]s
+     * @return list of selected chapters
      */
-    fun getSelectedChapters(): List<MangaChapter> {
-        return adapter.selectedItems.map { adapter.getItem(it) as? MangaChapter }.filterNotNull()
+    fun getSelectedChapters(): List<RecentChapter> {
+        return adapter.selectedItems.map { adapter.getItem(it) as? RecentChapter }.filterNotNull()
     }
 
     /**
@@ -142,7 +94,7 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
     override fun onListItemClick(position: Int): Boolean {
         // Get item from position
         val item = adapter.getItem(position)
-        if (item is MangaChapter) {
+        if (item is RecentChapter) {
             if (actionMode != null && adapter.mode == FlexibleAdapter.MODE_MULTI) {
                 toggleSelection(position)
                 return true
@@ -191,27 +143,27 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
 
     /**
      * Open chapter in reader
-     * @param mangaChapter selected [MangaChapter]
+     * @param chapter selected chapter
      */
-    private fun openChapter(mangaChapter: MangaChapter) {
-        val intent = ReaderActivity.newIntent(activity, mangaChapter.manga, mangaChapter.chapter)
+    private fun openChapter(chapter: RecentChapter) {
+        val intent = ReaderActivity.newIntent(activity, chapter.manga, chapter)
         startActivity(intent)
     }
 
     /**
      * Download selected items
-     * @param mangaChapters list of selected [MangaChapter]s
+     * @param chapters list of selected [RecentChapter]s
      */
-    fun downloadChapters(mangaChapters: List<MangaChapter>) {
+    fun downloadChapters(chapters: List<RecentChapter>) {
         destroyActionModeIfNeeded()
-        presenter.downloadChapters(mangaChapters)
+        presenter.downloadChapters(chapters)
     }
 
     /**
      * Populate adapter with chapters
      * @param chapters list of [Any]
      */
-    fun onNextMangaChapters(chapters: List<Any>) {
+    fun onNextRecentChapters(chapters: List<Any>) {
         (activity as MainActivity).updateEmptyView(chapters.isEmpty(),
                 R.string.information_no_recent, R.drawable.ic_update_black_128dp)
 
@@ -224,8 +176,7 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
      * @param download [Download] object containing download progress.
      */
     fun onChapterStatusChange(download: Download) {
-        getHolder(download)?.onStatusChange(download.status)
-
+        getHolder(download)?.notifyStatus(download.status)
     }
 
     /**
@@ -233,28 +184,28 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
      * @param download [Download] object containing download progress.
      */
     private fun getHolder(download: Download): RecentChaptersHolder? {
-        return recycler.findViewHolderForItemId(download.chapter.id) as? RecentChaptersHolder
+        return recycler.findViewHolderForItemId(download.chapter.id!!) as? RecentChaptersHolder
     }
 
     /**
      * Mark chapter as read
-     * @param mangaChapters list of [MangaChapter] objects
+     * @param chapters list of chapters
      */
-    fun markAsRead(mangaChapters: List<MangaChapter>) {
-        presenter.markChapterRead(mangaChapters, true)
+    fun markAsRead(chapters: List<RecentChapter>) {
+        presenter.markChapterRead(chapters, true)
         if (presenter.preferences.removeAfterMarkedAsRead()) {
-            deleteChapters(mangaChapters)
+            deleteChapters(chapters)
         }
     }
 
     /**
      * Delete selected chapters
-     * @param mangaChapters list of [MangaChapter] objects
+     * @param chapters list of [RecentChapter] objects
      */
-    fun deleteChapters(mangaChapters: List<MangaChapter>) {
+    fun deleteChapters(chapters: List<RecentChapter>) {
         destroyActionModeIfNeeded()
         DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
-        presenter.deleteChapters(mangaChapters)
+        presenter.deleteChapters(chapters)
     }
 
     /**
@@ -266,27 +217,27 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
 
     /**
      * Mark chapter as unread
-     * @param mangaChapters list of selected [MangaChapter]
+     * @param chapters list of selected [RecentChapter]
      */
-    fun markAsUnread(mangaChapters: List<MangaChapter>) {
-        presenter.markChapterRead(mangaChapters, false)
+    fun markAsUnread(chapters: List<RecentChapter>) {
+        presenter.markChapterRead(chapters, false)
     }
 
     /**
      * Start downloading chapter
-     * @param item selected chapter with manga
+     * @param chapter selected chapter with manga
      */
-    fun downloadChapter(item: MangaChapter) {
-        presenter.downloadChapter(item)
+    fun downloadChapter(chapter: RecentChapter) {
+        presenter.downloadChapter(chapter)
     }
 
     /**
      * Start deleting chapter
-     * @param item selected chapter with manga
+     * @param chapter selected chapter with manga
      */
-    fun deleteChapter(item: MangaChapter) {
+    fun deleteChapter(chapter: RecentChapter) {
         DeletingChaptersDialog().show(childFragmentManager, DeletingChaptersDialog.TAG)
-        presenter.deleteChapter(item)
+        presenter.deleteChapters(listOf(chapter))
     }
 
     /**
@@ -313,4 +264,52 @@ class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), Action
         (childFragmentManager.findFragmentByTag(DeletingChaptersDialog.TAG) as? DialogFragment)?.dismiss()
     }
 
+    override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
+        return false
+    }
+
+    /**
+     * Called when ActionMode item clicked
+     * @param mode the ActionMode object
+     * @param item item from ActionMode.
+     */
+    override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
+        when (item.itemId) {
+            R.id.action_mark_as_read -> markAsRead(getSelectedChapters())
+            R.id.action_mark_as_unread -> markAsUnread(getSelectedChapters())
+            R.id.action_download -> downloadChapters(getSelectedChapters())
+            R.id.action_delete -> {
+                MaterialDialog.Builder(activity)
+                        .content(R.string.confirm_delete_chapters)
+                        .positiveText(android.R.string.yes)
+                        .negativeText(android.R.string.no)
+                        .onPositive { dialog, action -> deleteChapters(getSelectedChapters()) }
+                        .show()
+            }
+            else -> return false
+        }
+        return true
+    }
+
+    /**
+     * Called when ActionMode created.
+     * @param mode the ActionMode object
+     * @param menu menu object of ActionMode
+     */
+    override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
+        mode.menuInflater.inflate(R.menu.chapter_recent_selection, menu)
+        adapter.mode = FlexibleAdapter.MODE_MULTI
+        return true
+    }
+
+    /**
+     * Called when ActionMode destroyed
+     * @param mode the ActionMode object
+     */
+    override fun onDestroyActionMode(mode: ActionMode?) {
+        adapter.mode = FlexibleAdapter.MODE_SINGLE
+        adapter.clearSelection()
+        actionMode = null
+    }
+
 }

+ 49 - 50
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersHolder.kt

@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.recent_updates
 import android.view.View
 import android.widget.PopupMenu
 import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.database.models.MangaChapter
 import eu.kanade.tachiyomi.data.download.model.Download
 import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
 import eu.kanade.tachiyomi.util.getResourceColor
@@ -19,8 +18,11 @@ import kotlinx.android.synthetic.main.item_recent_chapters.view.*
  * @param listener a listener to react to single tap and long tap events.
  * @constructor creates a new recent chapter holder.
  */
-class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapter, listener: OnListItemClickListener) :
-        FlexibleViewHolder(view, adapter, listener) {
+class RecentChaptersHolder(
+        private val view: View,
+        private val adapter: RecentChaptersAdapter,
+        listener: OnListItemClickListener)
+: FlexibleViewHolder(view, adapter, listener) {
     /**
      * Color of read chapter
      */
@@ -34,100 +36,97 @@ class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapte
     /**
      * Object containing chapter information
      */
-    private var mangaChapter: MangaChapter? = null
+    private var chapter: RecentChapter? = null
 
     init {
         // We need to post a Runnable to show the popup to make sure that the PopupMenu is
         // correctly positioned. The reason being that the view may change position before the
         // PopupMenu is shown.
-        itemView.chapter_menu.setOnClickListener { it.post({ showPopupMenu(it) }) }
+        view.chapter_menu.setOnClickListener { it.post({ showPopupMenu(it) }) }
     }
 
     /**
      * Set values of view
      *
-     * @param item item containing chapter information
+     * @param chapter item containing chapter information
      */
-    fun onSetValues(item: MangaChapter) {
-        this.mangaChapter = item
+    fun onSetValues(chapter: RecentChapter) {
+        this.chapter = chapter
 
         // Set chapter title
-        itemView.chapter_title.text = item.chapter.name
+        view.chapter_title.text = chapter.name
 
         // Set manga title
-        itemView.manga_title.text = item.manga.title
+        view.manga_title.text = chapter.manga.title
 
         // Check if chapter is read and set correct color
-        if (item.chapter.read) {
-            itemView.chapter_title.setTextColor(readColor)
-            itemView.manga_title.setTextColor(readColor)
+        if (chapter.read) {
+            view.chapter_title.setTextColor(readColor)
+            view.manga_title.setTextColor(readColor)
         } else {
-            itemView.chapter_title.setTextColor(unreadColor)
-            itemView.manga_title.setTextColor(unreadColor)
+            view.chapter_title.setTextColor(unreadColor)
+            view.manga_title.setTextColor(unreadColor)
         }
 
         // Set chapter status
-        onStatusChange(item.chapter.status)
+        notifyStatus(chapter.status)
     }
 
     /**
      * Updates chapter status in view.
-
+     *
      * @param status download status
      */
-    fun onStatusChange(status: Int) {
+    fun notifyStatus(status: Int) = with(view.download_text) {
         when (status) {
-            Download.QUEUE -> itemView.download_text.setText(R.string.chapter_queued)
-            Download.DOWNLOADING -> itemView.download_text.setText(R.string.chapter_downloading)
-            Download.DOWNLOADED -> itemView.download_text.setText(R.string.chapter_downloaded)
-            Download.ERROR -> itemView.download_text.setText(R.string.chapter_error)
-            else -> itemView.download_text.text = ""
+            Download.QUEUE -> setText(R.string.chapter_queued)
+            Download.DOWNLOADING -> setText(R.string.chapter_downloading)
+            Download.DOWNLOADED -> setText(R.string.chapter_downloaded)
+            Download.ERROR -> setText(R.string.chapter_error)
+            else -> text = ""
         }
     }
 
     /**
      * Show pop up menu
+     *
      * @param view view containing popup menu.
      */
-    private fun showPopupMenu(view: View) {
+    private fun showPopupMenu(view: View) = chapter?.let { chapter ->
         // Create a PopupMenu, giving it the clicked view for an anchor
-        val popup = PopupMenu(adapter.fragment.activity, view)
+        val popup = PopupMenu(view.context, view)
 
         // Inflate our menu resource into the PopupMenu's Menu
         popup.menuInflater.inflate(R.menu.chapter_recent, popup.menu)
 
-        mangaChapter?.let {
-
-            // Hide download and show delete if the chapter is downloaded and
-            if (it.chapter.isDownloaded) {
-                val menu = popup.menu
-                menu.findItem(R.id.action_download).isVisible = false
-                menu.findItem(R.id.action_delete).isVisible = true
-            }
-
-            // Hide mark as unread when the chapter is unread
-            if (!it.chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
-                popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
-            }
-
-            // Hide mark as read when the chapter is read
-            if (it.chapter.read) {
-                popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
-            }
+        // Hide download and show delete if the chapter is downloaded and
+        if (chapter.isDownloaded) {
+            popup.menu.findItem(R.id.action_download).isVisible = false
+            popup.menu.findItem(R.id.action_delete).isVisible = true
+        }
 
+        // Hide mark as unread when the chapter is unread
+        if (!chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
+            popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
+        }
 
-            // Set a listener so we are notified if a menu item is clicked
-            popup.setOnMenuItemClickListener { menuItem ->
+        // Hide mark as read when the chapter is read
+        if (chapter.read) {
+            popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
+        }
 
+        // Set a listener so we are notified if a menu item is clicked
+        popup.setOnMenuItemClickListener { menuItem ->
+            with(adapter.fragment) {
                 when (menuItem.itemId) {
-                    R.id.action_download -> adapter.fragment.downloadChapter(it)
-                    R.id.action_delete -> adapter.fragment.deleteChapter(it)
-                    R.id.action_mark_as_read -> adapter.fragment.markAsRead(listOf(it))
-                    R.id.action_mark_as_unread -> adapter.fragment.markAsUnread(listOf(it))
+                    R.id.action_download -> downloadChapter(chapter)
+                    R.id.action_delete -> deleteChapter(chapter)
+                    R.id.action_mark_as_read -> markAsRead(listOf(chapter))
+                    R.id.action_mark_as_unread -> markAsUnread(listOf(chapter))
                 }
-                true
             }
 
+            true
         }
 
         // Finally show the PopupMenu

+ 94 - 178
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChaptersPresenter.kt

@@ -2,8 +2,6 @@ package eu.kanade.tachiyomi.ui.recent_updates
 
 import android.os.Bundle
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.database.models.MangaChapter
 import eu.kanade.tachiyomi.data.download.DownloadManager
 import eu.kanade.tachiyomi.data.download.DownloadService
@@ -15,34 +13,34 @@ import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import timber.log.Timber
+import uy.kohesive.injekt.injectLazy
 import java.util.*
-import javax.inject.Inject
 
 class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
     /**
      * Used to connect to database
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     /**
      * Used to get settings
      */
-    @Inject lateinit var preferences: PreferencesHelper
+    val preferences: PreferencesHelper by injectLazy()
 
     /**
      * Used to get information from download manager
      */
-    @Inject lateinit var downloadManager: DownloadManager
+    val downloadManager: DownloadManager by injectLazy()
 
     /**
      * Used to get source from source id
      */
-    @Inject lateinit var sourceManager: SourceManager
+    val sourceManager: SourceManager by injectLazy()
 
     /**
      * List containing chapter and manga information
      */
-    private var mangaChapters: List<MangaChapter>? = null
+    private var chapters: List<RecentChapter>? = null
 
     /**
      * The id of the restartable.
@@ -60,171 +58,114 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
         // Used to get recent chapters
         restartableLatestCache(GET_RECENT_CHAPTERS,
                 { getRecentChaptersObservable() },
-                { fragment, chapters ->
+                { view, chapters ->
                     // Update adapter to show recent manga's
-                    fragment.onNextMangaChapters(chapters)
-                    // Update download status
-                    updateChapterStatus(convertToMangaChaptersList(chapters))
+                    view.onNextRecentChapters(chapters)
                 }
         )
 
         // Used to update download status
-        startableLatestCache(CHAPTER_STATUS_CHANGES,
-                { getChapterStatusObs() },
-                { recentChaptersFragment, download ->
+        restartableLatestCache(CHAPTER_STATUS_CHANGES,
+                { getChapterStatusObservable() },
+                { view, download ->
                     // Set chapter status
-                    recentChaptersFragment.onChapterStatusChange(download)
+                    view.onChapterStatusChange(download)
                 },
                 { view, error -> Timber.e(error.cause, error.message) }
         )
 
-
         if (savedState == null) {
             // Start fetching recent chapters
             start(GET_RECENT_CHAPTERS)
+            start(CHAPTER_STATUS_CHANGES)
         }
     }
 
+    /**
+     * Get observable containing recent chapters and date
+     * @return observable containing recent chapters and date
+     */
+    fun getRecentChaptersObservable(): Observable<ArrayList<Any>> {
+        // Set date for recent chapters
+        val cal = Calendar.getInstance().apply {
+            time = Date()
+            add(Calendar.MONTH, -1)
+        }
+
+        return db.getRecentChapters(cal.time).asRxObservable()
+                // Convert to a list of recent chapters.
+                .map { mangaChapters ->
+                    mangaChapters.map { it.toModel() }
+                }
+                .doOnNext { chapters = it }
+                // Group chapters by the date they were fetched on a ordered map.
+                .flatMap { recentItems ->
+                    Observable.from(recentItems)
+                            .toMultimap(
+                                    { getMapKey(it.date_fetch) },
+                                    { it },
+                                    { TreeMap { d1, d2 -> d2.compareTo(d1) } })
+                }
+                // Add every day and all its chapters to a single list.
+                .map { recentItems ->
+                    ArrayList<Any>().apply {
+                        for ((key, value) in recentItems) {
+                            add(key)
+                            addAll(value)
+                        }
+                    }
+                }
+                .observeOn(AndroidSchedulers.mainThread())
+    }
 
     /**
      * Returns observable containing chapter status.
      * @return download object containing download progress.
      */
-    private fun getChapterStatusObs(): Observable<Download> {
+    private fun getChapterStatusObservable(): Observable<Download> {
         return downloadManager.queue.getStatusObservable()
                 .observeOn(AndroidSchedulers.mainThread())
-                .filter { download: Download ->
-                    if (chapterIdEquals(download.chapter.id))
-                        true
-                    else
-                        false
-                }
-                .doOnNext { download1: Download -> updateChapterStatus(download1) }
-
+                .doOnNext { download -> onDownloadStatusChange(download) }
     }
 
     /**
-     * Function to check if chapter is in recent list
-     * @param chaptersId id of chapter
-     * @return exist in recent list
+     * Converts a chapter from the database to an extended model, allowing to store new fields.
      */
-    private fun chapterIdEquals(chaptersId: Long): Boolean {
-        mangaChapters!!.forEach { mangaChapter ->
-            if (chaptersId == mangaChapter.chapter.id) {
-                return true
-            }
-        }
-        return false
-    }
+    private fun MangaChapter.toModel(): RecentChapter {
+        // Create the model object.
+        val model = RecentChapter(this)
 
-    /**
-     * Returns a list only containing MangaChapter objects.
-     * @param input the list that will be converted.
-     * @return list containing MangaChapters objects.
-     */
-    private fun convertToMangaChaptersList(input: List<Any>): List<MangaChapter> {
-        // Create temp list
-        val tempMangaChapterList = ArrayList<MangaChapter>()
+        // Find an active download for this chapter.
+        val download = downloadManager.queue.find { it.chapter.id == chapter.id }
 
-        // Only add MangaChapter objects
-        //noinspection Convert2streamapi
-        input.forEach { `object` ->
-            if (`object` is MangaChapter) {
-                tempMangaChapterList.add(`object`)
-            }
-        }
+        // If there's an active download, assign it, otherwise ask the manager if the chapter is
+        // downloaded and assign it to the status.
+        if (download != null) {
+            model.download = download
+        } else {
+            // Get source of chapter.
+            val source = sourceManager.get(manga.source)!!
 
-        // Return temp list
-        return tempMangaChapterList
+            model.status = if (downloadManager.isChapterDownloaded(source, manga, chapter))
+                Download.DOWNLOADED
+            else
+                Download.NOT_DOWNLOADED
+        }
+        return model
     }
 
     /**
      * Update status of chapters.
      * @param download download object containing progress.
      */
-    private fun updateChapterStatus(download: Download) {
-        // Loop through list
-        mangaChapters?.let {
-            for (item in it) {
-                if (download.chapter.id == item.chapter.id) {
-                    // Update status.
-                    item.chapter.status = download.status
-                    break
-                }
-            }
-        }
-    }
-
-    /**
-     * Update status of chapters
-     * @param mangaChapters list containing recent chapters
-     */
-    private fun updateChapterStatus(mangaChapters: List<MangaChapter>) {
-        // Set global list of chapters.
-        this.mangaChapters = mangaChapters
-
-        // Update status.
-        //noinspection Convert2streamapi
-        for (mangaChapter in mangaChapters)
-            setChapterStatus(mangaChapter)
-
-        // Start onChapterStatusChange restartable.
-        start(CHAPTER_STATUS_CHANGES)
-    }
-
-    /**
-     * Set the chapter status
-     * @param mangaChapter MangaChapter which status gets updated
-     */
-    private fun setChapterStatus(mangaChapter: MangaChapter) {
-        // Check if chapter in queue
-        for (download in downloadManager.queue) {
-            if (mangaChapter.chapter.id == download.chapter.id) {
-                mangaChapter.chapter.status = download.status
-                return
+    private fun onDownloadStatusChange(download: Download) {
+        // Assign the download to the model object.
+        if (download.status == Download.QUEUE) {
+            val chapter = chapters?.find { it.id == download.chapter.id }
+            if (chapter != null && chapter.download == null) {
+                chapter.download = download
             }
         }
-
-        // Get source of chapter
-        val source = sourceManager.get(mangaChapter.manga.source)!!
-
-        // Check if chapter is downloaded
-        if (downloadManager.isChapterDownloaded(source, mangaChapter.manga, mangaChapter.chapter)) {
-            mangaChapter.chapter.status = Download.DOWNLOADED
-        } else {
-            mangaChapter.chapter.status = Download.NOT_DOWNLOADED
-        }
-    }
-
-    /**
-     * Get observable containing recent chapters and date
-     * @return observable containing recent chapters and date
-     */
-    fun getRecentChaptersObservable(): Observable<ArrayList<Any>>? {
-        // Set date for recent chapters
-        val cal = Calendar.getInstance()
-        cal.time = Date()
-        cal.add(Calendar.MONTH, -1)
-
-        return db.getRecentChapters(cal.time).asRxObservable()
-                // Group chapters by the date they were fetched on a ordered map.
-                .flatMap { recentItems ->
-                    Observable.from(recentItems)
-                            .toMultimap(
-                                    { getMapKey(it.chapter.date_fetch) },
-                                    { it },
-                                    { TreeMap { d1, d2 -> d2.compareTo(d1) } })
-                }
-                // Add every day and all its chapters to a single list.
-                .map { recentItems ->
-                    val items = ArrayList<Any>()
-                    recentItems.entries.forEach { recent ->
-                        items.add(recent.key)
-                        items.addAll(recent.value)
-                    }
-                    items
-                }
-                .observeOn(AndroidSchedulers.mainThread())
     }
 
     /**
@@ -244,18 +185,17 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
 
     /**
      * Mark selected chapter as read
-     * @param mangaChapters list of selected MangaChapters
+     * @param chapters list of selected chapters
      * @param read read status
      */
-    fun markChapterRead(mangaChapters: List<MangaChapter>, read: Boolean) {
-        Observable.from(mangaChapters)
-                .doOnNext { mangaChapter ->
-                    mangaChapter.chapter.read = read
+    fun markChapterRead(chapters: List<RecentChapter>, read: Boolean) {
+        Observable.from(chapters)
+                .doOnNext { chapter ->
+                    chapter.read = read
                     if (!read) {
-                        mangaChapter.chapter.last_page_read = 0
+                        chapter.last_page_read = 0
                     }
                 }
-                .map { mangaChapter -> mangaChapter.chapter }
                 .toList()
                 .flatMap { db.updateChaptersProgress(it).asRxObservable() }
                 .subscribeOn(Schedulers.io())
@@ -264,9 +204,9 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
 
     /**
      * Delete selected chapters
-     * @param chapters list of MangaChapters
+     * @param chapters list of chapters
      */
-    fun deleteChapters(chapters: List<MangaChapter>) {
+    fun deleteChapters(chapters: List<RecentChapter>) {
         val wasRunning = downloadManager.isRunning
         if (wasRunning) {
             DownloadService.stop(context)
@@ -288,11 +228,11 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
 
     /**
      * Download selected chapters
-     * @param mangaChapters [MangaChapter] that is selected
+     * @param chapters list of recent chapters seleted.
      */
-    fun downloadChapters(mangaChapters: List<MangaChapter>) {
+    fun downloadChapters(chapters: List<RecentChapter>) {
         DownloadService.start(context)
-        Observable.from(mangaChapters)
+        Observable.from(chapters)
                 .doOnNext { downloadChapter(it) }
                 .subscribeOn(AndroidSchedulers.mainThread())
                 .subscribe()
@@ -300,47 +240,23 @@ class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
 
     /**
      * Download selected chapter
-     * @param item chapter that is selected
+     * @param chapter chapter that is selected
      */
-    fun downloadChapter(item: MangaChapter) {
+    fun downloadChapter(chapter: RecentChapter) {
         DownloadService.start(context)
-        downloadManager.downloadChapters(item.manga, listOf(item.chapter))
-    }
-
-    /**
-     * Delete selected chapter
-     * @param item chapter that are selected
-     */
-    fun deleteChapter(item: MangaChapter) {
-        val wasRunning = downloadManager.isRunning
-        if (wasRunning) {
-            DownloadService.stop(context)
-        }
-        Observable.just(item)
-                .doOnNext { deleteChapter(it.chapter, it.manga) }
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribeFirst({ view, result ->
-                    view.onChaptersDeleted()
-                    if (wasRunning) {
-                        DownloadService.start(context)
-                    }
-                }, { view, error ->
-                    view.onChaptersDeletedError(error)
-                })
+        downloadManager.downloadChapters(chapter.manga, listOf(chapter))
     }
 
     /**
      * Delete selected chapter
      * @param chapter chapter that is selected
-     * @param manga manga that belongs to chapter
      */
-    private fun deleteChapter(chapter: Chapter, manga: Manga) {
-        val source = sourceManager.get(manga.source) ?: return
+    private fun deleteChapter(chapter: RecentChapter) {
+        val source = sourceManager.get(chapter.manga.source) ?: return
         downloadManager.queue.del(chapter)
-        downloadManager.deleteChapter(source, manga, chapter)
+        downloadManager.deleteChapter(source, chapter.manga, chapter)
         chapter.status = Download.NOT_DOWNLOADED
+        chapter.download = null
     }
 
-
 }

+ 3 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/SectionViewHolder.kt

@@ -2,11 +2,12 @@ package eu.kanade.tachiyomi.ui.recent_updates
 
 import android.support.v7.widget.RecyclerView
 import android.text.format.DateUtils
+import android.text.format.DateUtils.DAY_IN_MILLIS
 import android.view.View
 import kotlinx.android.synthetic.main.item_recent_chapter_section.view.*
 import java.util.*
 
-class SectionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+class SectionViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
 
     /**
      * Current date
@@ -19,8 +20,6 @@ class SectionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
      * @param date of section header
      */
     fun onSetValues(date: Date) {
-        val s = DateUtils.getRelativeTimeSpanString(
-                date.time, now, DateUtils.DAY_IN_MILLIS)
-        itemView.section_text.text = s
+        view.section_text.text = DateUtils.getRelativeTimeSpanString(date.time, now, DAY_IN_MILLIS)
     }
 }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt

@@ -37,8 +37,8 @@ class RecentlyReadHolder(view: View, private val adapter: RecentlyReadAdapter)
      */
     fun onSetValues(item: MangaChapterHistory) {
         // Retrieve objects
-        val manga = item.mangaChapter.manga
-        val chapter = item.mangaChapter.chapter
+        val manga = item.manga
+        val chapter = item.chapter
         val history = item.history
 
         // Set manga title
@@ -71,7 +71,7 @@ class RecentlyReadHolder(view: View, private val adapter: RecentlyReadAdapter)
                     .onPositive { materialDialog, dialogAction ->
                         // Check if user wants all chapters reset
                         if (materialDialog.customView?.removeAll?.isChecked as Boolean) {
-                            adapter.fragment.removeAllFromHistory(manga.id)
+                            adapter.fragment.removeAllFromHistory(manga.id!!)
                         } else {
                             adapter.fragment.removeFromHistory(history)
                         }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadPresenter.kt

@@ -9,9 +9,9 @@ import rx.Observable
 import rx.android.schedulers.AndroidSchedulers
 import rx.schedulers.Schedulers
 import timber.log.Timber
+import uy.kohesive.injekt.injectLazy
 import java.text.SimpleDateFormat
 import java.util.*
-import javax.inject.Inject
 
 /**
  * Presenter of RecentlyReadFragment.
@@ -30,7 +30,7 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadFragment>() {
     /**
      * Used to connect to database
      */
-    @Inject lateinit var db: DatabaseHelper
+    val db: DatabaseHelper by injectLazy()
 
     override fun onCreate(savedState: Bundle?) {
         super.onCreate(savedState)

+ 7 - 9
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsActivity.kt

@@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.setting
 
 import android.os.Bundle
 import android.support.v14.preference.PreferenceFragment
-import eu.kanade.tachiyomi.App
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.cache.ChapterCache
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
@@ -12,22 +11,21 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 import eu.kanade.tachiyomi.data.source.SourceManager
 import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
 import kotlinx.android.synthetic.main.toolbar.*
-import javax.inject.Inject
+import uy.kohesive.injekt.injectLazy
 
 class SettingsActivity : BaseActivity() {
 
-    @Inject lateinit var preferences: PreferencesHelper
-    @Inject lateinit var chapterCache: ChapterCache
-    @Inject lateinit var db: DatabaseHelper
-    @Inject lateinit var sourceManager: SourceManager
-    @Inject lateinit var syncManager: MangaSyncManager
-    @Inject lateinit var networkHelper: NetworkHelper
+    val preferences: PreferencesHelper by injectLazy()
+    val chapterCache: ChapterCache by injectLazy()
+    val db: DatabaseHelper by injectLazy()
+    val sourceManager: SourceManager by injectLazy()
+    val syncManager: MangaSyncManager by injectLazy()
+    val networkHelper: NetworkHelper by injectLazy()
 
     override fun onCreate(savedState: Bundle?) {
         setAppTheme()
         super.onCreate(savedState)
         setContentView(R.layout.activity_preferences)
-        App.get(this).component.inject(this)
 
         setupToolbar(toolbar)