Initial MergedSource creation UI
This commit is contained in:
parent
4c9be5557d
commit
10d6b3a6ca
@ -8,8 +8,6 @@ apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.github.zellius.shortcut-helper'
|
||||
// Realm (EH)
|
||||
apply plugin: 'realm-android'
|
||||
// Firebase (EH)
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
shortcutHelper.filePath = './shortcuts.xml'
|
||||
|
||||
@ -139,7 +137,8 @@ dependencies {
|
||||
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
|
||||
standardImplementation 'com.google.firebase:firebase-core:17.0.1'
|
||||
// DO NOT UPGRADE TO 17.0, IT REQUIRES ANDROIDX
|
||||
standardImplementation 'com.google.firebase:firebase-core:16.0.8'
|
||||
|
||||
// ReactiveX
|
||||
implementation 'io.reactivex:rxandroid:1.2.1'
|
||||
@ -174,6 +173,7 @@ dependencies {
|
||||
|
||||
// Job scheduling
|
||||
implementation 'com.evernote:android-job:1.2.5'
|
||||
// DO NOT UPGRADE TO 17.0, IT REQUIRES ANDROIDX
|
||||
implementation 'com.google.android.gms:play-services-gcm:15.0.1'
|
||||
|
||||
// Changelog
|
||||
@ -274,6 +274,7 @@ dependencies {
|
||||
|
||||
// RxJava 2 interop for Realm (EH)
|
||||
implementation 'com.lvla.android:rxjava2-interop-kt:0.2.1'
|
||||
implementation 'com.github.akarnokd:rxjava2-interop:0.13.7'
|
||||
|
||||
// Debug network interceptor (EH)
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:3.12.1"
|
||||
@ -297,6 +298,8 @@ dependencies {
|
||||
|
||||
// Humanize (EH)
|
||||
implementation 'com.github.mfornos:humanize-slim:1.2.2'
|
||||
|
||||
implementation 'com.android.support:gridlayout-v7:28.0.0'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
@ -319,4 +322,6 @@ androidExtensions {
|
||||
|
||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
// Firebase (EH)
|
||||
apply plugin: 'io.fabric'
|
||||
}
|
||||
|
@ -9,10 +9,7 @@ import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||
import eu.kanade.tachiyomi.source.online.all.PervEden
|
||||
import eu.kanade.tachiyomi.source.online.all.*
|
||||
import eu.kanade.tachiyomi.source.online.english.HentaiCafe
|
||||
import eu.kanade.tachiyomi.source.online.english.Tsumino
|
||||
import rx.Observable
|
||||
@ -51,6 +48,8 @@ open class SourceManager(private val context: Context) {
|
||||
Observable.merge(prefEntries).skip(prefEntries.size - 1).subscribe {
|
||||
createEHSources().forEach { registerSource(it) }
|
||||
}
|
||||
|
||||
registerSource(MergedSource())
|
||||
}
|
||||
|
||||
open fun get(sourceKey: Long): Source? {
|
||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.util.await
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -30,6 +31,8 @@ class MergedSource : HttpSource() {
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
private val gson: Gson by injectLazy()
|
||||
|
||||
override val id: Long = MERGED_SOURCE_ID
|
||||
|
||||
override val baseUrl = ""
|
||||
|
||||
override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException()
|
||||
@ -51,14 +54,16 @@ class MergedSource : HttpSource() {
|
||||
return GlobalScope.async(Dispatchers.IO) {
|
||||
val loadedMangas = readMangaConfig(manga).load(db, sourceManager).buffer()
|
||||
loadedMangas.map { loadedManga ->
|
||||
loadedManga.source.fetchChapterList(loadedManga.manga).map { chapterList ->
|
||||
chapterList.map { chapter ->
|
||||
chapter.apply {
|
||||
url = writeUrlConfig(UrlConfig(loadedManga.source.id, url, loadedManga.manga.url))
|
||||
async(Dispatchers.IO) {
|
||||
loadedManga.source.fetchChapterList(loadedManga.manga).map { chapterList ->
|
||||
chapterList.map { chapter ->
|
||||
chapter.apply {
|
||||
url = writeUrlConfig(UrlConfig(loadedManga.source.id, url, loadedManga.manga.url))
|
||||
}
|
||||
}
|
||||
}
|
||||
}.toSingle().await(Schedulers.io())
|
||||
}
|
||||
}.buffer().map { it.toSingle().await(Schedulers.io()) }.toList().flatten()
|
||||
}.buffer().map { it.await() }.toList().flatten()
|
||||
}.asSingle(Dispatchers.IO).toV1Single().toObservable()
|
||||
}
|
||||
override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException()
|
||||
@ -102,11 +107,12 @@ class MergedSource : HttpSource() {
|
||||
chapter.url = chapterConfig.url
|
||||
source.prepareNewChapter(chapter, copiedManga)
|
||||
chapter.url = writeUrlConfig(UrlConfig(source.id, chapter.url, chapterConfig.mangaUrl))
|
||||
chapter.scanlator = "${source.name}: ${chapter.scanlator}"
|
||||
chapter.scanlator = if(chapter.scanlator.isNullOrBlank()) source.name
|
||||
else "${source.name}: ${chapter.scanlator}"
|
||||
}
|
||||
|
||||
fun readMangaConfig(manga: SManga): MangaConfig {
|
||||
return gson.fromJson(manga.url)
|
||||
return MangaConfig.readFromUrl(gson, manga.url)
|
||||
}
|
||||
fun readUrlConfig(url: String): UrlConfig {
|
||||
return gson.fromJson(url)
|
||||
@ -126,11 +132,6 @@ class MergedSource : HttpSource() {
|
||||
val source = sourceManager.getOrStub(source)
|
||||
return LoadedMangaSource(source, manga)
|
||||
}
|
||||
companion object {
|
||||
fun fromLoadedMangaSource(loadedMS: LoadedMangaSource): MangaSource {
|
||||
return MangaSource(loadedMS.source.id, loadedMS.manga.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
data class MangaConfig(
|
||||
@SerializedName("c")
|
||||
@ -142,6 +143,16 @@ class MergedSource : HttpSource() {
|
||||
?: throw IllegalStateException("Missing source manga: $mangaSource")
|
||||
}
|
||||
}
|
||||
|
||||
fun writeAsUrl(gson: Gson): String {
|
||||
return gson.toJson(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun readFromUrl(gson: Gson, url: String): MangaConfig {
|
||||
return gson.fromJson(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
data class UrlConfig(
|
||||
@SerializedName("s")
|
||||
|
@ -257,7 +257,7 @@ class CatalogueController(bundle: Bundle? = null) : NucleusController<CatalogueP
|
||||
|
||||
// EXH -->
|
||||
@Parcelize
|
||||
data class SmartSearchConfig(val title: String) : Parcelable
|
||||
data class SmartSearchConfig(val origTitle: String, val origMangaId: Long) : Parcelable
|
||||
// EXH <--
|
||||
|
||||
enum class Mode {
|
||||
|
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.ui.manga.info.MangaWebViewController
|
||||
@ -50,11 +51,15 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
||||
ChangeMangaCategoriesDialog.Listener {
|
||||
|
||||
constructor(source: CatalogueSource,
|
||||
searchQuery: String? = null) : this(Bundle().apply {
|
||||
searchQuery: String? = null,
|
||||
smartSearchConfig: CatalogueController.SmartSearchConfig? = null) : this(Bundle().apply {
|
||||
putLong(SOURCE_ID_KEY, source.id)
|
||||
|
||||
if(searchQuery != null)
|
||||
putString(SEARCH_QUERY_KEY, searchQuery)
|
||||
|
||||
if (smartSearchConfig != null)
|
||||
putParcelable(SMART_SEARCH_CONFIG_KEY, smartSearchConfig)
|
||||
})
|
||||
|
||||
/**
|
||||
@ -561,7 +566,9 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
||||
*/
|
||||
override fun onItemClick(view: View, position: Int): Boolean {
|
||||
val item = adapter?.getItem(position) as? CatalogueItem ?: return false
|
||||
router.pushController(MangaController(item.manga, true).withFadeTransaction())
|
||||
router.pushController(MangaController(item.manga,
|
||||
true,
|
||||
args.getParcelable(SMART_SEARCH_CONFIG_KEY)).withFadeTransaction())
|
||||
|
||||
return false
|
||||
}
|
||||
@ -628,6 +635,9 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
||||
protected companion object {
|
||||
const val SOURCE_ID_KEY = "sourceId"
|
||||
const val SEARCH_QUERY_KEY = "searchQuery"
|
||||
// EXH -->
|
||||
const val SMART_SEARCH_CONFIG_KEY = "smartSearchConfig"
|
||||
// EXH <--
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.base.controller.RxController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersPresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
||||
@ -39,9 +40,14 @@ import java.util.Date
|
||||
|
||||
class MangaController : RxController, TabbedController {
|
||||
|
||||
constructor(manga: Manga?, fromCatalogue: Boolean = false) : super(Bundle().apply {
|
||||
constructor(manga: Manga?,
|
||||
fromCatalogue: Boolean = false,
|
||||
smartSearchConfig: CatalogueController.SmartSearchConfig? = null,
|
||||
update: Boolean = false) : super(Bundle().apply {
|
||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
||||
putParcelable(SMART_SEARCH_CONFIG_EXTRA, smartSearchConfig)
|
||||
putBoolean(UPDATE_EXTRA, update)
|
||||
}) {
|
||||
this.manga = manga
|
||||
if (manga != null) {
|
||||
@ -79,6 +85,10 @@ class MangaController : RxController, TabbedController {
|
||||
|
||||
val update = args.getBoolean(UPDATE_EXTRA, false)
|
||||
|
||||
// EXH -->
|
||||
val smartSearchConfig: CatalogueController.SmartSearchConfig? = args.getParcelable(SMART_SEARCH_CONFIG_EXTRA)
|
||||
// EXH <--
|
||||
|
||||
val lastUpdateRelay: BehaviorRelay<Date> = BehaviorRelay.create()
|
||||
|
||||
val chapterCountRelay: BehaviorRelay<Float> = BehaviorRelay.create()
|
||||
@ -197,6 +207,7 @@ class MangaController : RxController, TabbedController {
|
||||
|
||||
// EXH -->
|
||||
const val UPDATE_EXTRA = "update"
|
||||
const val SMART_SEARCH_CONFIG_EXTRA = "smartSearchConfig"
|
||||
// EXH <--
|
||||
const val FROM_CATALOGUE_EXTRA = "from_catalogue"
|
||||
const val MANGA_EXTRA = "manga"
|
||||
|
@ -22,6 +22,7 @@ import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.bumptech.glide.signature.ObjectKey
|
||||
import com.elvishew.xlog.XLog
|
||||
import com.google.gson.Gson
|
||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
|
||||
import com.jakewharton.rxbinding.view.clicks
|
||||
import com.jakewharton.rxbinding.view.longClicks
|
||||
@ -33,8 +34,10 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
@ -43,21 +46,21 @@ import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.openInBrowser
|
||||
import eu.kanade.tachiyomi.util.snack
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import eu.kanade.tachiyomi.util.truncateCenter
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.ui.webview.WebViewActivity
|
||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||
import jp.wasabeef.glide.transformations.MaskTransformation
|
||||
import kotlinx.android.synthetic.main.manga_info_controller.*
|
||||
import kotlinx.coroutines.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DateFormat
|
||||
import java.text.DecimalFormat
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Fragment that shows manga information.
|
||||
@ -65,7 +68,7 @@ import java.util.*
|
||||
* UI related actions should be called from here.
|
||||
*/
|
||||
class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
ChangeMangaCategoriesDialog.Listener {
|
||||
ChangeMangaCategoriesDialog.Listener, CoroutineScope {
|
||||
|
||||
/**
|
||||
* Preferences helper.
|
||||
@ -74,6 +77,14 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
|
||||
// EXH -->
|
||||
private var lastMangaThumbnail: String? = null
|
||||
|
||||
private val smartSearchConfig get() = (parentController as MangaController).smartSearchConfig
|
||||
|
||||
override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main
|
||||
|
||||
private val gson: Gson by injectLazy()
|
||||
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
// EXH <--
|
||||
|
||||
init {
|
||||
@ -83,7 +94,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
|
||||
override fun createPresenter(): MangaInfoPresenter {
|
||||
val ctrl = parentController as MangaController
|
||||
return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!,
|
||||
return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!, ctrl.smartSearchConfig,
|
||||
ctrl.chapterCountRelay, ctrl.lastUpdateRelay, ctrl.mangaFavoriteRelay)
|
||||
}
|
||||
|
||||
@ -153,6 +164,34 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
|
||||
}
|
||||
|
||||
// EXH -->
|
||||
smartSearchConfig?.let { smartSearchConfig ->
|
||||
smartsearch_buttons.visible()
|
||||
|
||||
smartsearch_merge_btn.clicks().subscribeUntilDestroy {
|
||||
// Init presenter here to avoid threading issues
|
||||
presenter
|
||||
|
||||
launch {
|
||||
try {
|
||||
val mergedManga = withContext(Dispatchers.IO + NonCancellable) {
|
||||
presenter.smartSearchMerge(presenter.manga, smartSearchConfig.origMangaId)
|
||||
}
|
||||
|
||||
parentController?.router?.pushController(MangaController(mergedManga,
|
||||
true,
|
||||
update = true).withFadeTransaction())
|
||||
applicationContext?.toast("Manga merged!")
|
||||
} catch(e: Exception) {
|
||||
if(e is CancellationException) throw e
|
||||
else {
|
||||
applicationContext?.toast("Failed to merge manga: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// EXH <--
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
@ -176,7 +215,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
|
||||
// EXH -->
|
||||
private fun openSmartSearch() {
|
||||
val smartSearchConfig = CatalogueController.SmartSearchConfig(presenter.manga.title)
|
||||
val smartSearchConfig = CatalogueController.SmartSearchConfig(presenter.manga.title, presenter.manga.id!!)
|
||||
|
||||
parentController?.router?.pushController(CatalogueController(Bundle().apply {
|
||||
putParcelable(CatalogueController.SMART_SEARCH_CONFIG, smartSearchConfig)
|
||||
@ -237,10 +276,24 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
// If manga source is known update source TextView.
|
||||
manga_source.text = if (source == null) {
|
||||
view.context.getString(R.string.unknown)
|
||||
// EXH -->
|
||||
} else if(source.id == MERGED_SOURCE_ID) {
|
||||
MergedSource.MangaConfig.readFromUrl(gson, manga.url).children.map {
|
||||
sourceManager.getOrStub(it.source).toString()
|
||||
}.distinct().joinToString()
|
||||
// EXH <--
|
||||
} else {
|
||||
source.toString()
|
||||
}
|
||||
|
||||
// EXH -->
|
||||
if(source?.id == MERGED_SOURCE_ID) {
|
||||
manga_source_label.text = "Sources"
|
||||
} else {
|
||||
manga_source_label.setText(R.string.manga_info_source_label)
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
// Update genres list
|
||||
if (manga.genre.isNullOrBlank().not()) {
|
||||
manga_genres_tags.setTags(manga.genre?.split(", "))
|
||||
@ -295,6 +348,13 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
||||
super.onDestroyView(view)
|
||||
}
|
||||
|
||||
// EXH -->
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cancel()
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
/**
|
||||
* Update chapter count TextView.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
package eu.kanade.tachiyomi.ui.manga.info
|
||||
|
||||
import android.os.Bundle
|
||||
import com.google.gson.Gson
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
@ -10,8 +11,14 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.util.await
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@ -28,12 +35,14 @@ import java.util.*
|
||||
class MangaInfoPresenter(
|
||||
val manga: Manga,
|
||||
val source: Source,
|
||||
val smartSearchConfig: CatalogueController.SmartSearchConfig?,
|
||||
private val chapterCountRelay: BehaviorRelay<Float>,
|
||||
private val lastUpdateRelay: BehaviorRelay<Date>,
|
||||
private val mangaFavoriteRelay: PublishRelay<Boolean>,
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get()
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val gson: Gson = Injekt.get()
|
||||
) : BasePresenter<MangaInfoController>() {
|
||||
|
||||
/**
|
||||
@ -170,4 +179,59 @@ class MangaInfoPresenter(
|
||||
moveMangaToCategories(manga, listOfNotNull(category))
|
||||
}
|
||||
|
||||
suspend fun smartSearchMerge(manga: Manga, originalMangaId: Long): Manga {
|
||||
val originalManga = db.getManga(originalMangaId).await()
|
||||
?: throw IllegalArgumentException("Unknown manga ID: $originalMangaId")
|
||||
val toInsert = if(originalManga.source == MERGED_SOURCE_ID) {
|
||||
originalManga.apply {
|
||||
val originalChildren = MergedSource.MangaConfig.readFromUrl(gson, url).children
|
||||
if(originalChildren.any { it.source == manga.source && it.url == manga.url })
|
||||
throw IllegalArgumentException("This manga is already merged with the current manga!")
|
||||
|
||||
url = MergedSource.MangaConfig(originalChildren + MergedSource.MangaSource(
|
||||
manga.source,
|
||||
manga.url
|
||||
)).writeAsUrl(gson)
|
||||
}
|
||||
} else {
|
||||
val newMangaConfig = MergedSource.MangaConfig(listOf(
|
||||
MergedSource.MangaSource(
|
||||
originalManga.source,
|
||||
originalManga.url
|
||||
),
|
||||
MergedSource.MangaSource(
|
||||
manga.source,
|
||||
manga.url
|
||||
)
|
||||
))
|
||||
Manga.create(newMangaConfig.writeAsUrl(gson), originalManga.title, MERGED_SOURCE_ID).apply {
|
||||
copyFrom(originalManga)
|
||||
favorite = true
|
||||
last_update = originalManga.last_update
|
||||
viewer = originalManga.viewer
|
||||
chapter_flags = originalManga.chapter_flags
|
||||
sorting = Manga.SORTING_NUMBER
|
||||
}
|
||||
}
|
||||
|
||||
// Note that if the manga are merged in a different order, this won't trigger, but I don't care lol
|
||||
val existingManga = db.getManga(toInsert.url, toInsert.source).await()
|
||||
if(existingManga != null) {
|
||||
withContext(NonCancellable) {
|
||||
if(toInsert.id != null) {
|
||||
db.deleteManga(toInsert).await()
|
||||
}
|
||||
}
|
||||
|
||||
return existingManga
|
||||
}
|
||||
|
||||
// Reload chapters immediately
|
||||
toInsert.initialized = false
|
||||
|
||||
val newId = db.insertManga(toInsert).await().insertedId()
|
||||
if(newId != null) toInsert.id = newId
|
||||
|
||||
return toInsert
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ const val NHENTAI_SOURCE_ID = LEWD_SOURCE_SERIES + 7
|
||||
val HENTAI_CAFE_SOURCE_ID = delegatedSourceId<HentaiCafe>()
|
||||
const val TSUMINO_SOURCE_ID = LEWD_SOURCE_SERIES + 9
|
||||
const val HITOMI_SOURCE_ID = LEWD_SOURCE_SERIES + 10
|
||||
const val MERGED_SOURCE_ID = LEWD_SOURCE_SERIES + 69
|
||||
|
||||
private val DELEGATED_LEWD_SOURCES = listOf(
|
||||
HentaiCafe::class
|
||||
|
@ -50,7 +50,7 @@ class SmartSearchController(bundle: Bundle? = null) : NucleusController<SmartSea
|
||||
for(event in presenter.smartSearchChannel) {
|
||||
withContext(NonCancellable) {
|
||||
if (event is SmartSearchPresenter.SearchResults.Found) {
|
||||
val transaction = MangaController(event.manga, true).withFadeTransaction()
|
||||
val transaction = MangaController(event.manga, true, smartSearchConfig).withFadeTransaction()
|
||||
withContext(Dispatchers.Main) {
|
||||
router.replaceTopController(transaction)
|
||||
}
|
||||
@ -61,7 +61,7 @@ class SmartSearchController(bundle: Bundle? = null) : NucleusController<SmartSea
|
||||
applicationContext?.toast("Error performing automatic search!")
|
||||
}
|
||||
|
||||
val transaction = BrowseCatalogueController(source, smartSearchConfig.title).withFadeTransaction()
|
||||
val transaction = BrowseCatalogueController(source, smartSearchConfig.origTitle, smartSearchConfig).withFadeTransaction()
|
||||
withContext(Dispatchers.Main) {
|
||||
router.replaceTopController(transaction)
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class SmartSearchPresenter(private val source: CatalogueSource?, private val con
|
||||
}
|
||||
|
||||
private suspend fun smartSearch(source: CatalogueSource, config: CatalogueController.SmartSearchConfig): SManga? {
|
||||
val cleanedTitle = cleanSmartSearchTitle(config.title)
|
||||
val cleanedTitle = cleanSmartSearchTitle(config.origTitle)
|
||||
|
||||
val queries = getSmartSearchQueries(cleanedTitle)
|
||||
|
||||
|
@ -254,6 +254,35 @@
|
||||
app:atg_textColor="@color/md_blue_A400"
|
||||
android:layout_marginRight="64dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/smartsearch_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_genres_tags"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_merge_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Merge with current" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_replace_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Replace current" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
|
@ -9,11 +9,8 @@
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<View
|
||||
android:id="@+id/guideline"
|
||||
@ -230,12 +227,10 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/manga_source_label"
|
||||
app:layout_constraintLeft_toRightOf="@+id/manga_source_label"
|
||||
app:layout_constraintRight_toRightOf="parent"/>
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/manga_status_label" />
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
||||
@ -287,7 +282,34 @@
|
||||
app:atg_borderStrokeWidth="1dp"
|
||||
app:atg_backgroundColor="@android:color/transparent"
|
||||
app:atg_borderColor="@color/md_blue_A400"
|
||||
app:atg_textColor="@color/md_blue_A400" />
|
||||
app:atg_textColor="@color/md_blue_A400" >
|
||||
|
||||
</me.gujun.android.taggroup.TagGroup>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/smartsearch_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_merge_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Merge with current" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/smartsearch_replace_btn"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Replace current" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user