Show manga with no installed source. Based on PR #1345

This commit is contained in:
inorichi 2018-06-30 19:55:46 +02:00
parent fd825b1049
commit 3d1afe7cf2
11 changed files with 67 additions and 29 deletions

View File

@ -33,7 +33,8 @@ import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
@ -295,7 +296,7 @@ class BackupRestoreService : Service() {
categories: List<String>, history: List<DHistory>, categories: List<String>, history: List<DHistory>,
tracks: List<Track>): Observable<Manga>? { tracks: List<Track>): Observable<Manga>? {
// Get source // Get source
val source = backupManager.sourceManager.get(manga.source) ?: return null val source = backupManager.sourceManager.getOrStub(manga.source)
val dbManga = backupManager.getMangaFromDatabase(manga) val dbManga = backupManager.getMangaFromDatabase(manga)
return if (dbManga == null) { return if (dbManga == null) {
@ -441,4 +442,4 @@ class BackupRestoreService : Service() {
sendLocalBroadcast(intent) sendLocalBroadcast(intent)
} }
} }

View File

@ -1,17 +1,24 @@
package eu.kanade.tachiyomi.source package eu.kanade.tachiyomi.source
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.source.online.english.* import eu.kanade.tachiyomi.source.online.english.*
import eu.kanade.tachiyomi.source.online.german.WieManga import eu.kanade.tachiyomi.source.online.german.WieManga
import eu.kanade.tachiyomi.source.online.russian.Mangachan import eu.kanade.tachiyomi.source.online.russian.Mangachan
import eu.kanade.tachiyomi.source.online.russian.Mintmanga import eu.kanade.tachiyomi.source.online.russian.Mintmanga
import eu.kanade.tachiyomi.source.online.russian.Readmanga import eu.kanade.tachiyomi.source.online.russian.Readmanga
import rx.Observable
open class SourceManager(private val context: Context) { open class SourceManager(private val context: Context) {
private val sourcesMap = mutableMapOf<Long, Source>() private val sourcesMap = mutableMapOf<Long, Source>()
private val stubSourcesMap = mutableMapOf<Long, StubSource>()
init { init {
createInternalSources().forEach { registerSource(it) } createInternalSources().forEach { registerSource(it) }
} }
@ -20,13 +27,19 @@ open class SourceManager(private val context: Context) {
return sourcesMap[sourceKey] return sourcesMap[sourceKey]
} }
fun getOrStub(sourceKey: Long): Source {
return sourcesMap[sourceKey] ?: stubSourcesMap.getOrPut(sourceKey) {
StubSource(sourceKey)
}
}
fun getOnlineSources() = sourcesMap.values.filterIsInstance<HttpSource>() fun getOnlineSources() = sourcesMap.values.filterIsInstance<HttpSource>()
fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>() fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>()
internal fun registerSource(source: Source, overwrite: Boolean = false) { internal fun registerSource(source: Source, overwrite: Boolean = false) {
if (overwrite || !sourcesMap.containsKey(source.id)) { if (overwrite || !sourcesMap.containsKey(source.id)) {
sourcesMap.put(source.id, source) sourcesMap[source.id] = source
} }
} }
@ -47,4 +60,30 @@ open class SourceManager(private val context: Context) {
Mangasee(), Mangasee(),
WieManga() WieManga()
) )
private inner class StubSource(override val id: Long) : Source {
override val name: String
get() = id.toString()
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return Observable.error(getSourceNotInstalledException())
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return Observable.error(getSourceNotInstalledException())
}
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
return Observable.error(getSourceNotInstalledException())
}
override fun toString(): String {
return name
}
private fun getSourceNotInstalledException(): Exception {
return Exception(context.getString(R.string.source_not_installed, id.toString()))
}
}
} }

View File

@ -25,7 +25,9 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.* import java.util.ArrayList
import java.util.Collections
import java.util.Comparator
/** /**
* Class containing library information. * Class containing library information.
@ -113,9 +115,6 @@ class LibraryPresenter(
val filterCompleted = preferences.filterCompleted().getOrDefault() val filterCompleted = preferences.filterCompleted().getOrDefault()
val filterFn: (LibraryItem) -> Boolean = f@ { item -> val filterFn: (LibraryItem) -> Boolean = f@ { item ->
// Filter out manga without source.
sourceManager.get(item.manga.source) ?: return@f false
// Filter when there isn't unread chapters. // Filter when there isn't unread chapters.
if (filterUnread && item.manga.unread == 0) { if (filterUnread && item.manga.unread == 0) {
return@f false return@f false
@ -197,8 +196,8 @@ class LibraryPresenter(
manga1TotalChapter.compareTo(mange2TotalChapter) manga1TotalChapter.compareTo(mange2TotalChapter)
} }
LibrarySort.SOURCE -> { LibrarySort.SOURCE -> {
val source1Name = sourceManager.get(i1.manga.source)?.name ?: "" val source1Name = sourceManager.getOrStub(i1.manga.source).name
val source2Name = sourceManager.get(i2.manga.source)?.name ?: "" val source2Name = sourceManager.getOrStub(i2.manga.source).name
source1Name.compareTo(source2Name) source1Name.compareTo(source2Name)
} }
else -> throw Exception("Unknown sorting mode") else -> throw Exception("Unknown sorting mode")

View File

@ -34,7 +34,7 @@ import kotlinx.android.synthetic.main.manga_controller.*
import rx.Subscription import rx.Subscription
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.* import java.util.Date
class MangaController : RxController, TabbedController { class MangaController : RxController, TabbedController {
@ -44,7 +44,7 @@ class MangaController : RxController, TabbedController {
}) { }) {
this.manga = manga this.manga = manga
if (manga != null) { if (manga != null) {
source = Injekt.get<SourceManager>().get(manga.source) source = Injekt.get<SourceManager>().getOrStub(manga.source)
} }
} }

View File

@ -71,7 +71,7 @@ class MigrationPresenter(
private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> { private fun findSourcesWithManga(library: List<Manga>): List<SourceItem> {
val header = SelectionHeader() val header = SelectionHeader()
return library.map { it.source }.toSet() return library.map { it.source }.toSet()
.mapNotNull { if (it != LocalSource.ID) sourceManager.get(it) else null } .mapNotNull { if (it != LocalSource.ID) sourceManager.getOrStub(it) else null }
.map { SourceItem(it, header) } .map { SourceItem(it, header) }
} }

View File

@ -32,7 +32,8 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.File import java.io.File
import java.net.URLConnection import java.net.URLConnection
import java.util.* import java.util.Comparator
import java.util.Date
/** /**
* Presenter of [ReaderActivity]. * Presenter of [ReaderActivity].
@ -74,7 +75,7 @@ class ReaderPresenter(
/** /**
* Source of the manga. * Source of the manga.
*/ */
private val source by lazy { sourceManager.get(manga.source)!! } private val source by lazy { sourceManager.getOrStub(manga.source) }
/** /**
* Chapter list for the active manga. It's retrieved lazily and should be accessed for the first * Chapter list for the active manga. It's retrieved lazily and should be accessed for the first

View File

@ -14,7 +14,9 @@ import rx.schedulers.Schedulers
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.* import java.util.Calendar
import java.util.Date
import java.util.TreeMap
class RecentChaptersPresenter( class RecentChaptersPresenter(
val preferences: PreferencesHelper = Injekt.get(), val preferences: PreferencesHelper = Injekt.get(),
@ -57,7 +59,6 @@ class RecentChaptersPresenter(
.map { mangaChapters -> .map { mangaChapters ->
val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) } val map = TreeMap<Date, MutableList<MangaChapter>> { d1, d2 -> d2.compareTo(d1) }
val byDay = mangaChapters val byDay = mangaChapters
.filter { sourceManager.get(it.manga.source) != null }
.groupByTo(map, { getMapKey(it.chapter.date_fetch) }) .groupByTo(map, { getMapKey(it.chapter.date_fetch) })
byDay.flatMap { byDay.flatMap {
val dateItem = DateItem(it.key) val dateItem = DateItem(it.key)
@ -195,4 +196,4 @@ class RecentChaptersPresenter(
item.download = null item.download = null
} }
} }

View File

@ -7,7 +7,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.recently_read_item.* import kotlinx.android.synthetic.main.recently_read_item.*
import java.util.* import java.util.Date
/** /**
* Holder that contains recent manga item * Holder that contains recent manga item
@ -52,7 +52,7 @@ class RecentlyReadHolder(
// Set source + chapter title // Set source + chapter title
val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble()) val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
manga_source.text = itemView.context.getString(R.string.recent_manga_source) manga_source.text = itemView.context.getString(R.string.recent_manga_source)
.format(adapter.sourceManager.get(manga.source)?.toString(), formattedNumber) .format(adapter.sourceManager.getOrStub(manga.source).toString(), formattedNumber)
// Set last read timestamp title // Set last read timestamp title
last_read.text = adapter.dateFormat.format(Date(history.last_read)) last_read.text = adapter.dateFormat.format(Date(history.last_read))

View File

@ -5,12 +5,13 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import rx.Observable import rx.Observable
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.* import java.util.Calendar
import java.util.Comparator
import java.util.Date
/** /**
* Presenter of RecentlyReadFragment. * Presenter of RecentlyReadFragment.
@ -24,8 +25,6 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
*/ */
val db: DatabaseHelper by injectLazy() val db: DatabaseHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
override fun onCreate(savedState: Bundle?) { override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState) super.onCreate(savedState)
@ -45,10 +44,7 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
cal.add(Calendar.MONTH, -1) cal.add(Calendar.MONTH, -1)
return db.getRecentManga(cal.time).asRxObservable() return db.getRecentManga(cal.time).asRxObservable()
.map { recents -> .map { recents -> recents.map(::RecentlyReadItem) }
recents.filter { sourceManager.get(it.manga.source) != null }
.map(::RecentlyReadItem)
}
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }

View File

@ -349,6 +349,7 @@
<string name="icon_creation_fail">Failed to create shortcut!</string> <string name="icon_creation_fail">Failed to create shortcut!</string>
<string name="delete_downloads_for_manga">Delete downloaded chapters?</string> <string name="delete_downloads_for_manga">Delete downloaded chapters?</string>
<string name="copied_to_clipboard">%1$s copied to clipboard</string> <string name="copied_to_clipboard">%1$s copied to clipboard</string>
<string name="source_not_installed">Source not installed: %1$s</string>
<!-- Manga chapters fragment --> <!-- Manga chapters fragment -->
<string name="manga_chapters_tab">Chapters</string> <string name="manga_chapters_tab">Chapters</string>

View File

@ -7,7 +7,7 @@ buildscript {
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0' classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0'
classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2' classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2'
classpath 'com.google.gms:google-services:3.2.0' classpath 'com.google.gms:google-services:3.2.0'