Rewrite link intercept activity

Fix compatibility issues between lewd sources and manga info screen
This commit is contained in:
NerdNumber9
2018-01-29 15:39:34 -05:00
parent 8c8f2585aa
commit f18b32626a
19 changed files with 240 additions and 132 deletions

View File

@ -1,3 +1,10 @@
### 6.8.0
- Various performance improvements
- Fix library search query being lost
- Upstream merge
- Fix Tsumino and HentaiCafe links not triggering a link import
- Fix many bugs in link interceptor
### 6.6.0 ### 6.6.0
- Many performance improvements - Many performance improvements
- Stability improvements and bug fixes - Stability improvements and bug fixes

View File

@ -105,7 +105,8 @@
<!-- EH --> <!-- EH -->
<activity <activity
android:name="exh.ui.intercept.InterceptActivity" android:name="exh.ui.intercept.InterceptActivity"
android:label="TachiyomiEH"> android:excludeFromRecents="true"
android:label="Tachiyomi">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -146,21 +147,35 @@
android:scheme="https"/> android:scheme="https"/>
<data <data
android:host="www.perveden.com" android:host="www.perveden.com"
android:pathPattern="/.*/.*-manga/.*"
android:scheme="http"/> android:scheme="http"/>
<data <data
android:host="www.perveden.com" android:host="www.perveden.com"
android:pathPattern="/.*/.*-manga/.*"
android:scheme="https"/> android:scheme="https"/>
<data <data
android:host="hentai.cafe" android:host="hentai.cafe"
android:pathPattern="/.*/.*"
android:scheme="http"/> android:scheme="http"/>
<data <data
android:host="hentai.cafe" android:host="hentai.cafe"
android:pathPattern="/.*/.*"
android:scheme="https"/> android:scheme="https"/>
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/"
android:scheme="http"/> android:scheme="http"/>
<data <data
android:host="www.tsumino.com" android:host="www.tsumino.com"
android:pathPrefix="/Book/Info/"
android:scheme="https"/>
<data
android:host="www.tsumino.com"
android:pathPrefix="/Read/View/"
android:scheme="http"/>
<data
android:host="www.tsumino.com"
android:pathPrefix="/Read/View/"
android:scheme="https"/> android:scheme="https"/>
</intent-filter> </intent-filter>
</activity> </activity>

View File

@ -7,7 +7,11 @@ import eu.kanade.tachiyomi.source.online.LewdSource
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.ChapterRecognition import eu.kanade.tachiyomi.util.ChapterRecognition
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import exh.metadata.models.* import exh.metadata.EMULATED_TAG_NAMESPACE
import exh.metadata.models.PervEdenGalleryMetadata
import exh.metadata.models.PervEdenLang
import exh.metadata.models.PervEdenTitle
import exh.metadata.models.Tag
import exh.util.UriFilter import exh.util.UriFilter
import exh.util.UriGroup import exh.util.UriGroup
import exh.util.urlImportFetchSearchManga import exh.util.urlImportFetchSearchManga
@ -139,7 +143,7 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang) : ParsedHttpSour
} }
"Genres" -> { "Genres" -> {
if(it is Element && it.tagName() == "a") if(it is Element && it.tagName() == "a")
tags.add(Tag("genre", it.text().toLowerCase(), false)) tags.add(Tag(EMULATED_TAG_NAMESPACE, it.text().toLowerCase(), false))
} }
"Type" -> { "Type" -> {
if(it is TextNode) { if(it is TextNode) {

View File

@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.source.online.LewdSource
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import exh.HENTAI_CAFE_SOURCE_ID import exh.HENTAI_CAFE_SOURCE_ID
import exh.metadata.EMULATED_TAG_NAMESPACE
import exh.metadata.models.HentaiCafeMetadata import exh.metadata.models.HentaiCafeMetadata
import exh.metadata.models.HentaiCafeMetadata.Companion.BASE_URL import exh.metadata.models.HentaiCafeMetadata.Companion.BASE_URL
import exh.metadata.models.Tag import exh.metadata.models.Tag
@ -128,7 +129,7 @@ class HentaiCafe : ParsedHttpSource(), LewdSource<HentaiCafeMetadata, Document>
val firstPath = parsed.pathSegments.first() val firstPath = parsed.pathSegments.first()
when(firstPath) { when(firstPath) {
"tag" -> tags.add(Tag("tag", it.text(), false)) "tag" -> tags.add(Tag(EMULATED_TAG_NAMESPACE, it.text(), false))
"artist" -> { "artist" -> {
artist = it.text() artist = it.text()
tags.add(Tag("artist", it.text(), false)) tags.add(Tag("artist", it.text(), false))

View File

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.source.online.LewdSource
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import exh.TSUMINO_SOURCE_ID import exh.TSUMINO_SOURCE_ID
import exh.metadata.EMULATED_TAG_NAMESPACE
import exh.metadata.models.Tag import exh.metadata.models.Tag
import exh.metadata.models.TsuminoMetadata import exh.metadata.models.TsuminoMetadata
import exh.metadata.models.TsuminoMetadata.Companion.BASE_URL import exh.metadata.models.TsuminoMetadata.Companion.BASE_URL
@ -96,7 +97,7 @@ class Tsumino: ParsedHttpSource(), LewdSource<TsuminoMetadata, Document> {
it.getElementById("Tag")?.children()?.let { it.getElementById("Tag")?.children()?.let {
tags.addAll(it.map { tags.addAll(it.map {
Tag("tag", it.text().trim(), false) Tag(EMULATED_TAG_NAMESPACE, it.text().trim(), false)
}) })
} }
} }

View File

@ -36,11 +36,11 @@ import eu.kanade.tachiyomi.ui.migration.MigrationController
import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.widget.DrawerSwipeCloseListener import eu.kanade.tachiyomi.widget.DrawerSwipeCloseListener
import exh.FavoritesSyncHelper
import exh.metadata.loadAllMetadata import exh.metadata.loadAllMetadata
import exh.metadata.models.SearchableGalleryMetadata import exh.metadata.models.SearchableGalleryMetadata
import io.realm.Realm import io.realm.Realm
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.android.synthetic.main.main_activity.*
import kotlinx.android.synthetic.main.library_controller.* import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import rx.Subscription import rx.Subscription
@ -133,6 +133,8 @@ class LibraryController(
var realm: Realm? = null var realm: Realm? = null
//Cached metadata //Cached metadata
var meta: Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>>? = null var meta: Map<KClass<out SearchableGalleryMetadata>, RealmResults<out SearchableGalleryMetadata>>? = null
//Favorites
val favorites by lazy { FavoritesSyncHelper(activity!!) }
// <-- EH // <-- EH
init { init {
@ -403,6 +405,9 @@ class LibraryController(
R.id.action_source_migration -> { R.id.action_source_migration -> {
router.pushController(MigrationController().withFadeTransaction()) router.pushController(MigrationController().withFadeTransaction())
} }
R.id.action_download_favorites -> {
favorites.guiSyncFavorites { }
}
else -> return super.onOptionsItemSelected(item) else -> return super.onOptionsItemSelected(item)
} }

View File

@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SManga 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.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
@ -45,6 +46,8 @@ import eu.kanade.tachiyomi.util.getResourceColor
import eu.kanade.tachiyomi.util.snack import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.util.truncateCenter import eu.kanade.tachiyomi.util.truncateCenter
import exh.EH_SOURCE_ID
import exh.EXH_SOURCE_ID
import jp.wasabeef.glide.transformations.CropSquareTransformation import jp.wasabeef.glide.transformations.CropSquareTransformation
import jp.wasabeef.glide.transformations.MaskTransformation import jp.wasabeef.glide.transformations.MaskTransformation
import kotlinx.android.synthetic.main.manga_info_controller.* import kotlinx.android.synthetic.main.manga_info_controller.*
@ -66,6 +69,8 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
*/ */
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
init { init {
setHasOptionsMenu(true) setHasOptionsMenu(true)
setOptionsMenuHidden(true) setOptionsMenuHidden(true)
@ -103,22 +108,38 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
} }
manga_artist.clicks().subscribeUntilDestroy { manga_artist.clicks().subscribeUntilDestroy {
performGlobalSearch(manga_artist.text.toString()) //EXH Special case E-Hentai/ExHentai to use tag based search
var text = manga_artist.text.toString()
if(isEHentaiBasedSource())
text = wrapTag("artist", text)
performGlobalSearch(text)
} }
manga_author.longClicks().subscribeUntilDestroy { manga_author.longClicks().subscribeUntilDestroy {
copyToClipboard(manga_author.text.toString(), manga_author.text.toString()) //EXH Special case E-Hentai/ExHentai to ignore author field (unused)
if(!isEHentaiBasedSource())
copyToClipboard(manga_author.text.toString(), manga_author.text.toString())
} }
manga_author.clicks().subscribeUntilDestroy { manga_author.clicks().subscribeUntilDestroy {
performGlobalSearch(manga_author.text.toString()) //EXH Special case E-Hentai/ExHentai to ignore author field (unused)
if(!isEHentaiBasedSource())
performGlobalSearch(manga_author.text.toString())
} }
manga_summary.longClicks().subscribeUntilDestroy { manga_summary.longClicks().subscribeUntilDestroy {
copyToClipboard(view.context.getString(R.string.description), manga_summary.text.toString()) copyToClipboard(view.context.getString(R.string.description), manga_summary.text.toString())
} }
manga_genres_tags.setOnTagClickListener { tag -> performGlobalSearch(tag) } manga_genres_tags.setOnTagClickListener { tag ->
//EXH Special case E-Hentai/ExHentai to use tag based search
var text = tag
if(isEHentaiBasedSource()) {
val parsed = parseTag(text)
text = wrapTag(parsed.first, parsed.second)
}
performGlobalSearch(text)
}
manga_cover.longClicks().subscribeUntilDestroy { manga_cover.longClicks().subscribeUntilDestroy {
copyToClipboard(view.context.getString(R.string.title), presenter.manga.title) copyToClipboard(view.context.getString(R.string.title), presenter.manga.title)
@ -491,6 +512,32 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
router.pushController(CatalogueSearchController(query).withFadeTransaction()) router.pushController(CatalogueSearchController(query).withFadeTransaction())
} }
// --> EH
private fun wrapTag(namespace: String, tag: String)
= if(tag.contains(' '))
"$namespace:\"$tag$\""
else
"$namespace:$tag$"
private fun parseTag(tag: String) = tag.substringBefore(':').trim() to tag.substringAfter(':').trim()
private fun isEHentaiBasedSource(): Boolean {
val mangaSourceText = manga_source.text
sourceManager.get(EH_SOURCE_ID)?.let {
if(mangaSourceText.startsWith(it.name))
return true
}
sourceManager.get(EXH_SOURCE_ID)?.let {
if(mangaSourceText.startsWith(it.name))
return true
}
return false
}
// <-- EH
/** /**
* Create shortcut using ShortcutManager. * Create shortcut using ShortcutManager.
* *

View File

@ -5,6 +5,7 @@ import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
import exh.ui.login.LoginController import exh.ui.login.LoginController
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
/** /**
* EH Settings fragment * EH Settings fragment
@ -22,6 +23,7 @@ class SettingsEhController : SettingsController() {
defaultValue = false defaultValue = false
preferences.enableExhentai() preferences.enableExhentai()
.asObservable() .asObservable()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribeUntilDestroy { .subscribeUntilDestroy {
isChecked = it isChecked = it

View File

@ -74,8 +74,10 @@ class FavoritesSyncHelper(val activity: Activity) {
(exSource ?: ehSource)?.let { source -> (exSource ?: ehSource)?.let { source ->
val favResponse = source.fetchFavorites() val favResponse = source.fetchFavorites()
val ourCategories = ArrayList<Category>(db.getCategories().executeAsBlocking()) val ourCategories = db.getCategories().executeAsBlocking().toMutableList()
val ourMangas = ArrayList<Manga>(db.getMangas().executeAsBlocking()) val ourMangas = db.getMangas().executeAsBlocking().filter {
it.source == EH_SOURCE_ID || it.source == EXH_SOURCE_ID
}.toMutableList()
//Add required categories (categories do not sync upwards) //Add required categories (categories do not sync upwards)
favResponse.second.filter { theirCategory -> favResponse.second.filter { theirCategory ->
ourCategories.find { ourCategories.find {
@ -93,7 +95,7 @@ class FavoritesSyncHelper(val activity: Activity) {
val categoryMap = (it + ourCategories).associateBy { it.name } val categoryMap = (it + ourCategories).associateBy { it.name }
//Insert new mangas //Insert new mangas
val mangaToInsert = java.util.ArrayList<Manga>() val mangaToInsert = mutableListOf<Manga>()
favResponse.first.map { favResponse.first.map {
val category = categoryMap[it.fav]!! val category = categoryMap[it.fav]!!
var manga = it.manga var manga = it.manga

View File

@ -83,3 +83,11 @@ fun buildTagsDescription(metadata: SearchableGalleryMetadata)
} }
} }
} }
fun joinTagsToGenreString(metadata: SearchableGalleryMetadata)
= metadata.tags.joinToString { "${it.namespace}: ${it.name}" }
fun joinEmulatedTagsToGenreString(metadata: SearchableGalleryMetadata)
= metadata.tags.filter { it.namespace == EMULATED_TAG_NAMESPACE }.joinToString { it.name.toString() }
val EMULATED_TAG_NAMESPACE = "tag"

View File

@ -4,10 +4,7 @@ import android.net.Uri
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.EX_DATE_FORMAT import exh.metadata.*
import exh.metadata.ONGOING_SUFFIX
import exh.metadata.buildTagsDescription
import exh.metadata.humanReadableByteCount
import exh.plusAssign import exh.plusAssign
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
@ -110,12 +107,9 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
tags.filter { it.namespace == EH_ARTIST_NAMESPACE }.let { tags.filter { it.namespace == EH_ARTIST_NAMESPACE }.let {
if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! }) if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! })
} }
//Set author (if we can find one)
tags.filter { it.namespace == EH_AUTHOR_NAMESPACE }.let { //Copy tags -> genres
if(it.isNotEmpty()) manga.author = it.joinToString(transform = { it.name!! }) manga.genre = joinTagsToGenreString(this)
}
//Set genre
genre?.let { manga.genre = it }
//Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes //Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes
//We default to completed //We default to completed
@ -134,6 +128,7 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
altTitle?.let { titleDesc += "Alternate Title: $it\n" } altTitle?.let { titleDesc += "Alternate Title: $it\n" }
val detailsDesc = StringBuilder() val detailsDesc = StringBuilder()
genre?.let { detailsDesc += "Genre: $it\n" }
uploader?.let { detailsDesc += "Uploader: $it\n" } uploader?.let { detailsDesc += "Uploader: $it\n" }
datePosted?.let { detailsDesc += "Posted: ${EX_DATE_FORMAT.format(Date(it))}\n" } datePosted?.let { detailsDesc += "Posted: ${EX_DATE_FORMAT.format(Date(it))}\n" }
visible?.let { detailsDesc += "Visible: $it\n" } visible?.let { detailsDesc += "Visible: $it\n" }
@ -176,7 +171,6 @@ open class ExGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
) )
private const val EH_ARTIST_NAMESPACE = "artist" private const val EH_ARTIST_NAMESPACE = "artist"
private const val EH_AUTHOR_NAMESPACE = "author"
} }
} }

View File

@ -3,10 +3,7 @@ package exh.metadata.models
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.EX_DATE_FORMAT import exh.metadata.*
import exh.metadata.ONGOING_SUFFIX
import exh.metadata.buildTagsDescription
import exh.metadata.nullIfBlank
import exh.plusAssign import exh.plusAssign
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
@ -106,10 +103,14 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! }) if(it.isNotEmpty()) manga.artist = it.joinToString(transform = { it.name!! })
} }
var category: String? = null
tags.filter { it.namespace == NHENTAI_CATEGORIES_NAMESPACE }.let { tags.filter { it.namespace == NHENTAI_CATEGORIES_NAMESPACE }.let {
if(it.isNotEmpty()) manga.genre = it.joinToString(transform = { it.name!! }) if(it.isNotEmpty()) category = it.joinToString(transform = { it.name!! })
} }
//Copy tags -> genres
manga.genre = joinEmulatedTagsToGenreString(this)
//Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes //Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes
//We default to completed //We default to completed
manga.status = SManga.COMPLETED manga.status = SManga.COMPLETED
@ -127,6 +128,7 @@ open class NHentaiMetadata : RealmObject(), SearchableGalleryMetadata {
shortTitle?.let { titleDesc += "Short Title: $it\n" } shortTitle?.let { titleDesc += "Short Title: $it\n" }
val detailsDesc = StringBuilder() val detailsDesc = StringBuilder()
category?.let { detailsDesc += "Category: $it\n" }
uploadDate?.let { detailsDesc += "Upload Date: ${EX_DATE_FORMAT.format(Date(it * 1000))}\n" } uploadDate?.let { detailsDesc += "Upload Date: ${EX_DATE_FORMAT.format(Date(it * 1000))}\n" }
pageImageTypes.size.let { detailsDesc += "Length: $it pages\n" } pageImageTypes.size.let { detailsDesc += "Length: $it pages\n" }
favoritesCount?.let { detailsDesc += "Favorited: $it times\n" } favoritesCount?.let { detailsDesc += "Favorited: $it times\n" }

View File

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.source.model.SManga
import exh.PERV_EDEN_EN_SOURCE_ID import exh.PERV_EDEN_EN_SOURCE_ID
import exh.PERV_EDEN_IT_SOURCE_ID import exh.PERV_EDEN_IT_SOURCE_ID
import exh.metadata.buildTagsDescription import exh.metadata.buildTagsDescription
import exh.metadata.joinEmulatedTagsToGenreString
import exh.plusAssign import exh.plusAssign
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
@ -77,7 +78,6 @@ open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
} }
type?.let { type?.let {
manga.genre = it
detailsDesc += "Type: $it\n" detailsDesc += "Type: $it\n"
} }
@ -94,6 +94,9 @@ open class PervEdenGalleryMetadata : RealmObject(), SearchableGalleryMetadata {
detailsDesc += "Rating: %.2\n".format(it) detailsDesc += "Rating: %.2\n".format(it)
} }
//Copy tags -> genres
manga.genre = joinEmulatedTagsToGenreString(this)
val tagsDesc = buildTagsDescription(this) val tagsDesc = buildTagsDescription(this)
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString()) manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
@ -164,6 +167,7 @@ open class PervEdenTitle(var metadata: PervEdenGalleryMetadata? = null,
} }
enum class PervEdenLang(val id: Long) { enum class PervEdenLang(val id: Long) {
//DO NOT RENAME THESE TO CAPITAL LETTERS! The enum names are used to build URLs
en(PERV_EDEN_EN_SOURCE_ID), en(PERV_EDEN_EN_SOURCE_ID),
it(PERV_EDEN_IT_SOURCE_ID); it(PERV_EDEN_IT_SOURCE_ID);

View File

@ -4,6 +4,7 @@ import android.net.Uri
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import exh.metadata.EX_DATE_FORMAT import exh.metadata.EX_DATE_FORMAT
import exh.metadata.buildTagsDescription import exh.metadata.buildTagsDescription
import exh.metadata.joinEmulatedTagsToGenreString
import exh.plusAssign import exh.plusAssign
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
@ -96,7 +97,6 @@ open class TsuminoMetadata : RealmObject(), SearchableGalleryMetadata {
length?.let { detailsDesc += "Length: $it pages\n" } length?.let { detailsDesc += "Length: $it pages\n" }
ratingString?.let { detailsDesc += "Rating: $it\n" } ratingString?.let { detailsDesc += "Rating: $it\n" }
category?.let { category?.let {
manga.genre = it
detailsDesc += "Category: $it\n" detailsDesc += "Category: $it\n"
} }
collection?.let { detailsDesc += "Collection: $it\n" } collection?.let { detailsDesc += "Collection: $it\n" }
@ -109,7 +109,10 @@ open class TsuminoMetadata : RealmObject(), SearchableGalleryMetadata {
if(charactersString.isNotEmpty()) { if(charactersString.isNotEmpty()) {
detailsDesc += "Character: $charactersString\n" detailsDesc += "Character: $charactersString\n"
} }
//Copy tags -> genres
manga.genre = joinEmulatedTagsToGenreString(this)
val tagsDesc = buildTagsDescription(this) val tagsDesc = buildTagsDescription(this)
manga.description = listOf(titleDesc, detailsDesc.toString(), tagsDesc.toString()) manga.description = listOf(titleDesc, detailsDesc.toString(), tagsDesc.toString())

View File

@ -5,32 +5,19 @@ import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import exh.GalleryAddEvent
import exh.GalleryAdder
import kotlinx.android.synthetic.main.eh_activity_intercept.* import kotlinx.android.synthetic.main.eh_activity_intercept.*
import uy.kohesive.injekt.injectLazy import nucleus.factory.RequiresPresenter
import kotlin.concurrent.thread import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
class InterceptActivity : BaseActivity() { @RequiresPresenter(InterceptActivityPresenter::class)
class InterceptActivity : BaseRxActivity<InterceptActivityPresenter>() {
private val preferences: PreferencesHelper by injectLazy() private var statusSubscription: Subscription? = null
private val galleryAdder = GalleryAdder()
var finished = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
//Set theme
setTheme(when (preferences.theme()) {
2 -> R.style.Theme_Tachiyomi_Dark
3 -> R.style.Theme_Tachiyomi_Amoled
else -> R.style.Theme_Tachiyomi
})
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.eh_activity_intercept) setContentView(R.layout.eh_activity_intercept)
@ -38,37 +25,12 @@ class InterceptActivity : BaseActivity() {
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
if(savedInstanceState == null) processLink()
thread { processLink() }
} }
private fun processLink() { private fun processLink() {
if(Intent.ACTION_VIEW == intent.action) { if(Intent.ACTION_VIEW == intent.action)
val result = galleryAdder.addGallery(intent.dataString) presenter.loadGallery(intent.dataString)
when(result) {
is GalleryAddEvent.Success ->
if(!finished)
startActivity(Intent(this, MainActivity::class.java)
.setAction(MainActivity.SHORTCUT_MANGA)
.putExtra(MangaController.MANGA_EXTRA, result.manga.id))
is GalleryAddEvent.Fail ->
if(!finished)
runOnUiThread {
MaterialDialog.Builder(this)
.title("Error")
.content("Could not open this gallery:\n\n${result.logMessage}")
.cancelable(true)
.canceledOnTouchOutside(true)
.cancelListener { onBackPressed() }
.positiveText("Ok")
.onPositive { _, _ -> onBackPressed() }
.dismissListener { onBackPressed() }
.show()
}
}
onBackPressed()
}
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -79,15 +41,36 @@ class InterceptActivity : BaseActivity() {
return true return true
} }
override fun onBackPressed() { override fun onStart() {
if(!finished) super.onStart()
runOnUiThread { statusSubscription?.unsubscribe()
super.onBackPressed() statusSubscription = presenter.status
} .observeOn(AndroidSchedulers.mainThread())
.subscribe {
when(it) {
is InterceptResult.Success -> {
startActivity(Intent(this, MainActivity::class.java)
.setAction(MainActivity.SHORTCUT_MANGA)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(MangaController.MANGA_EXTRA, it.mangaId))
onBackPressed()
}
is InterceptResult.Failure ->
MaterialDialog.Builder(this)
.title("Error")
.content("Could not open this gallery:\n\n${it.reason}")
.cancelable(true)
.canceledOnTouchOutside(true)
.positiveText("Ok")
.cancelListener { onBackPressed() }
.dismissListener { onBackPressed() }
.show()
}
}
} }
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
finished = true statusSubscription?.unsubscribe()
} }
} }

View File

@ -0,0 +1,40 @@
package exh.ui.intercept
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import exh.GalleryAddEvent
import exh.GalleryAdder
import rx.subjects.BehaviorSubject
import kotlin.concurrent.thread
class InterceptActivityPresenter : BasePresenter<InterceptActivity>() {
private val galleryAdder = GalleryAdder()
val status = BehaviorSubject.create<InterceptResult>(InterceptResult.Idle())
@Synchronized
fun loadGallery(gallery: String) {
//Do not load gallery if already loading
if(status.value is InterceptResult.Idle) {
status.onNext(InterceptResult.Loading())
//Load gallery async
thread {
val result = galleryAdder.addGallery(gallery)
status.onNext(when (result) {
is GalleryAddEvent.Success -> result.manga.id?.let {
InterceptResult.Success(it)
} ?: InterceptResult.Failure("Manga ID is null!")
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
})
}
}
}
}
sealed class InterceptResult {
class Idle : InterceptResult()
class Loading : InterceptResult()
data class Success(val mangaId: Long): InterceptResult()
data class Failure(val reason: String): InterceptResult()
}

View File

@ -15,7 +15,8 @@
<android.support.design.widget.AppBarLayout <android.support.design.widget.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
app:elevation="0dp">
<android.support.v7.widget.Toolbar <android.support.v7.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
@ -27,28 +28,29 @@
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
<FrameLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
<LinearLayout android:layout_gravity="center"
android:layout_height="wrap_content" android:background="?attr/colorPrimary"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:orientation="vertical" android:layout_height="wrap_content"
android:layout_gravity="center"> android:layout_marginBottom="8dp"
android:text="Loading gallery..."
android:textAppearance="@style/TextAppearance.Medium.Title"
android:textColor="@color/white" />
<TextView <ProgressBar
android:text="Loading gallery..." style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.Medium.Title" /> android:layout_gravity="center"
android:indeterminateTint="@color/white" />
<ProgressBar </LinearLayout>
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</LinearLayout>
</FrameLayout>
</LinearLayout> </LinearLayout>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

View File

@ -240,7 +240,7 @@
<android.support.v4.widget.NestedScrollView <android.support.v4.widget.NestedScrollView
android:id="@+id/description_scrollview" android:id="@+id/description_scrollview"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
@ -249,7 +249,8 @@
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/guideline"> app:layout_constraintTop_toBottomOf="@+id/guideline"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -273,33 +274,20 @@
android:focusable="true" android:focusable="true"
android:longClickable="true"/> android:longClickable="true"/>
<me.gujun.android.taggroup.TagGroup
android:id="@+id/manga_genres_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/TagGroup"
app:atg_borderStrokeWidth="1dp"
app:atg_backgroundColor="@android:color/transparent"
app:atg_borderColor="@color/md_blue_A400"
app:atg_textColor="@color/md_blue_A400" />
</LinearLayout> </LinearLayout>
</android.support.v4.widget.NestedScrollView> </android.support.v4.widget.NestedScrollView>
<me.gujun.android.taggroup.TagGroup
android:id="@+id/manga_genres_tags"
style="@style/TagGroup"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="16dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description_scrollview"
app:layout_constraintBottom_toBottomOf="parent"
app:atg_borderStrokeWidth="1dp"
app:atg_backgroundColor="@android:color/transparent"
app:atg_borderColor="@color/md_blue_A400"
app:atg_textColor="@color/md_blue_A400"
/>
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.SwipeRefreshLayout> </android.support.v4.widget.SwipeRefreshLayout>

View File

@ -23,7 +23,7 @@
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>
<item <item
android:id="@+id/action_sync" android:id="@+id/action_download_favorites"
android:icon="@drawable/ic_cloud_download_white_24dp" android:icon="@drawable/ic_cloud_download_white_24dp"
android:title="Download favorites" android:title="Download favorites"
app:showAsAction="ifRoom"/> app:showAsAction="ifRoom"/>