Add a special view to replace descriptions for integrated and delegated sources!
As the integrated and delegated websites don't actually have descriptions, just info, I decided to make a special view for them! with all the info you need available to you in front of your face, there is now no need to go searching through the description! This is likely the most work I have put into 1 feature in the whole time I have been developing TachiyomiSY!
This commit is contained in:
parent
a38cb2ab5f
commit
3e9c8dbfd2
@ -1,14 +1,18 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
package eu.kanade.tachiyomi.source.online
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
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.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadata
|
||||||
|
import exh.source.EnhancedHttpSource
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
@ -102,6 +106,24 @@ interface LewdSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDescriptionAdapter(controller: MangaController): RecyclerView.Adapter<*>?
|
||||||
|
|
||||||
val SManga.id get() = (this as? Manga)?.id
|
val SManga.id get() = (this as? Manga)?.id
|
||||||
val SChapter.mangaId get() = (this as? Chapter)?.manga_id
|
val SChapter.mangaId get() = (this as? Chapter)?.manga_id
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun Source.isLewdSource() = (this is LewdSource<*, *> || (this is EnhancedHttpSource && this.enhancedSource is LewdSource<*, *>))
|
||||||
|
|
||||||
|
fun Source.getLewdSource(): LewdSource<*, *>? {
|
||||||
|
return if (!this.isLewdSource()) {
|
||||||
|
null
|
||||||
|
} else if (this is LewdSource<*, *>) {
|
||||||
|
this
|
||||||
|
} else if (this is EnhancedHttpSource && this.enhancedSource is LewdSource<*, *>) {
|
||||||
|
this.enhancedSource
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.debug.DebugToggles
|
import exh.debug.DebugToggles
|
||||||
import exh.eh.EHTags
|
import exh.eh.EHTags
|
||||||
@ -36,11 +37,13 @@ import exh.metadata.metadata.EHentaiSearchMetadata
|
|||||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.EH_GENRE_NAMESPACE
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.EH_GENRE_NAMESPACE
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_WEAK
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.metadata.nullIfBlank
|
import exh.metadata.nullIfBlank
|
||||||
import exh.metadata.parseHumanReadableByteCount
|
import exh.metadata.parseHumanReadableByteCount
|
||||||
import exh.ui.login.LoginController
|
import exh.ui.login.LoginController
|
||||||
|
import exh.ui.metadata.adapters.EHentaiDescriptionAdapter
|
||||||
import exh.util.UriFilter
|
import exh.util.UriFilter
|
||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
import exh.util.asObservableWithAsyncStacktrace
|
import exh.util.asObservableWithAsyncStacktrace
|
||||||
@ -477,6 +480,8 @@ class EHentai(
|
|||||||
element.text().trim(),
|
element.text().trim(),
|
||||||
if (element.hasClass("gtl")) {
|
if (element.hasClass("gtl")) {
|
||||||
TAG_TYPE_LIGHT
|
TAG_TYPE_LIGHT
|
||||||
|
} else if (element.hasClass("gtw")) {
|
||||||
|
TAG_TYPE_WEAK
|
||||||
} else {
|
} else {
|
||||||
TAG_TYPE_NORMAL
|
TAG_TYPE_NORMAL
|
||||||
}
|
}
|
||||||
@ -832,6 +837,10 @@ class EHentai(
|
|||||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
|
return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): EHentaiDescriptionAdapter {
|
||||||
|
return EHentaiDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
private const val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
||||||
private const val TR_SUFFIX = "TR"
|
private const val TR_SUFFIX = "TR"
|
||||||
|
@ -18,6 +18,7 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.HITOMI_SOURCE_ID
|
import exh.HITOMI_SOURCE_ID
|
||||||
import exh.hitomi.HitomiNozomi
|
import exh.hitomi.HitomiNozomi
|
||||||
@ -27,6 +28,7 @@ import exh.metadata.metadata.HitomiSearchMetadata.Companion.LTN_BASE_URL
|
|||||||
import exh.metadata.metadata.HitomiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.HitomiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
|
import exh.ui.metadata.adapters.HitomiDescriptionAdapter
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -422,6 +424,10 @@ class Hitomi(val context: Context) : HttpSource(), LewdSource<HitomiSearchMetada
|
|||||||
return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html"
|
return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): HitomiDescriptionAdapter {
|
||||||
|
return HitomiDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val INDEX_VERSION_CACHE_TIME_MS = 1000 * 60 * 10
|
private val INDEX_VERSION_CACHE_TIME_MS = 1000 * 60 * 10
|
||||||
private val PAGE_SIZE = 25
|
private val PAGE_SIZE = 25
|
||||||
|
@ -21,11 +21,14 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.NHENTAI_SOURCE_ID
|
import exh.NHENTAI_SOURCE_ID
|
||||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.NHentaiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.NHentaiSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
|
import exh.ui.metadata.adapters.NHentaiDescriptionAdapter
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
@ -195,7 +198,7 @@ class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMeta
|
|||||||
tags.clear()
|
tags.clear()
|
||||||
}?.forEach {
|
}?.forEach {
|
||||||
if (it.first != null && it.second != null) {
|
if (it.first != null && it.second != null) {
|
||||||
tags.add(RaisedTag(it.first!!, it.second!!, TAG_TYPE_DEFAULT))
|
tags.add(RaisedTag(it.first!!, it.second!!, if (it.first == "category") TAG_TYPE_VIRTUAL else TAG_TYPE_DEFAULT))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,6 +369,10 @@ class NHentai(val context: Context) : HttpSource(), LewdSource<NHentaiSearchMeta
|
|||||||
return "$baseUrl/g/${uri.pathSegments[1]}/"
|
return "$baseUrl/g/${uri.pathSegments[1]}/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): NHentaiDescriptionAdapter {
|
||||||
|
return NHentaiDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val GALLERY_JSON_REGEX = Regex(".parse\\(\"(.*)\"\\);")
|
private val GALLERY_JSON_REGEX = Regex(".parse\\(\"(.*)\"\\);")
|
||||||
private val UNICODE_ESCAPE_REGEX = Regex("\\\\u([0-9a-fA-F]{4})")
|
private val UNICODE_ESCAPE_REGEX = Regex("\\\\u([0-9a-fA-F]{4})")
|
||||||
|
@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
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.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
||||||
import exh.metadata.metadata.PervEdenLang
|
import exh.metadata.metadata.PervEdenLang
|
||||||
@ -20,6 +21,7 @@ import exh.metadata.metadata.PervEdenSearchMetadata
|
|||||||
import exh.metadata.metadata.PervEdenSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.PervEdenSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
|
import exh.ui.metadata.adapters.PervEdenDescriptionAdapter
|
||||||
import exh.util.UriFilter
|
import exh.util.UriFilter
|
||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -358,6 +360,10 @@ class PervEden(override val id: Long, val pvLang: PervEdenLang, val context: Con
|
|||||||
return newUri.toString()
|
return newUri.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): PervEdenDescriptionAdapter {
|
||||||
|
return PervEdenDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val DATE_FORMAT = SimpleDateFormat("MMM d, yyyy", Locale.US).apply {
|
val DATE_FORMAT = SimpleDateFormat("MMM d, yyyy", Locale.US).apply {
|
||||||
timeZone = TimeZone.getTimeZone("GMT")
|
timeZone = TimeZone.getTimeZone("GMT")
|
||||||
|
@ -14,10 +14,12 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.EIGHTMUSES_SOURCE_ID
|
import exh.EIGHTMUSES_SOURCE_ID
|
||||||
import exh.metadata.metadata.EightMusesSearchMetadata
|
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
|
import exh.ui.metadata.adapters.EightMusesDescriptionAdapter
|
||||||
import exh.util.CachedField
|
import exh.util.CachedField
|
||||||
import exh.util.NakedTrie
|
import exh.util.NakedTrie
|
||||||
import exh.util.await
|
import exh.util.await
|
||||||
@ -397,4 +399,8 @@ class EightMuses(val context: Context) :
|
|||||||
}
|
}
|
||||||
return "/comics/album/${path.joinToString("/")}"
|
return "/comics/album/${path.joinToString("/")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): EightMusesDescriptionAdapter {
|
||||||
|
return EightMusesDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.HBROWSE_SOURCE_ID
|
import exh.HBROWSE_SOURCE_ID
|
||||||
import exh.metadata.metadata.HBrowseSearchMetadata
|
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||||
@ -25,6 +26,7 @@ import exh.metadata.metadata.base.RaisedTag
|
|||||||
import exh.search.Namespace
|
import exh.search.Namespace
|
||||||
import exh.search.SearchEngine
|
import exh.search.SearchEngine
|
||||||
import exh.search.Text
|
import exh.search.Text
|
||||||
|
import exh.ui.metadata.adapters.HBrowseDescriptionAdapter
|
||||||
import exh.util.await
|
import exh.util.await
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -475,6 +477,10 @@ class HBrowse(val context: Context) : HttpSource(), LewdSource<HBrowseSearchMeta
|
|||||||
return "$baseUrl/${uri.pathSegments.first()}"
|
return "$baseUrl/${uri.pathSegments.first()}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): HBrowseDescriptionAdapter {
|
||||||
|
return HBrowseDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val PAGE_LIST_REGEX = Regex("list *= *(\\[.*]);")
|
private val PAGE_LIST_REGEX = Regex("list *= *(\\[.*]);")
|
||||||
private val TOTAL_PAGES_REGEX = Regex("totalPages *= *([0-9]*);")
|
private val TOTAL_PAGES_REGEX = Regex("totalPages *= *([0-9]*);")
|
||||||
|
@ -9,12 +9,14 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.HentaiCafeSearchMetadata
|
import exh.metadata.metadata.HentaiCafeSearchMetadata
|
||||||
import exh.metadata.metadata.HentaiCafeSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.HentaiCafeSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
|
import exh.ui.metadata.adapters.HentaiCafeDescriptionAdapter
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
@ -111,4 +113,8 @@ class HentaiCafe(delegate: HttpSource, val context: Context) :
|
|||||||
"https://hentai.cafe/$lcFirstPathSegment"
|
"https://hentai.cafe/$lcFirstPathSegment"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): HentaiCafeDescriptionAdapter {
|
||||||
|
return HentaiCafeDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,13 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.PururinSearchMetadata
|
import exh.metadata.metadata.PururinSearchMetadata
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
|
import exh.ui.metadata.adapters.PururinDescriptionAdapter
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.trimAll
|
import exh.util.trimAll
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -89,10 +92,11 @@ class Pururin(delegate: HttpSource, val context: Context) :
|
|||||||
else -> {
|
else -> {
|
||||||
value.select("a").forEach { link ->
|
value.select("a").forEach { link ->
|
||||||
val searchUrl = Uri.parse(link.attr("href"))
|
val searchUrl = Uri.parse(link.attr("href"))
|
||||||
|
val namespace = searchUrl.pathSegments[searchUrl.pathSegments.lastIndex - 2]
|
||||||
tags += RaisedTag(
|
tags += RaisedTag(
|
||||||
searchUrl.pathSegments[searchUrl.pathSegments.lastIndex - 2],
|
namespace,
|
||||||
searchUrl.lastPathSegment!!.substringBefore("."),
|
searchUrl.lastPathSegment!!.substringBefore("."),
|
||||||
PururinSearchMetadata.TAG_TYPE_DEFAULT
|
if (namespace != PururinSearchMetadata.TAG_NAMESPACE_CATEGORY) PururinSearchMetadata.TAG_TYPE_DEFAULT else TAG_TYPE_VIRTUAL
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,4 +113,8 @@ class Pururin(delegate: HttpSource, val context: Context) :
|
|||||||
override fun mapUrlToMangaUrl(uri: Uri): String? {
|
override fun mapUrlToMangaUrl(uri: Uri): String? {
|
||||||
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments[1]}/${uri.lastPathSegment}"
|
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments[1]}/${uri.lastPathSegment}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): PururinDescriptionAdapter {
|
||||||
|
return PururinDescriptionAdapter(controller)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,12 +9,14 @@ 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.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.TsuminoSearchMetadata
|
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||||
import exh.metadata.metadata.TsuminoSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
import exh.metadata.metadata.TsuminoSearchMetadata.Companion.TAG_TYPE_DEFAULT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
|
import exh.ui.metadata.adapters.TsuminoDescriptionAdapter
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.trimAll
|
import exh.util.trimAll
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -83,6 +85,12 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
|||||||
|
|
||||||
input.getElementById("Rating")?.text()?.let {
|
input.getElementById("Rating")?.text()?.let {
|
||||||
ratingString = it.trim()
|
ratingString = it.trim()
|
||||||
|
val ratingString = ratingString
|
||||||
|
if (!ratingString.isNullOrBlank()) {
|
||||||
|
averageRating = RATING_FLOAT_REGEX.find(ratingString)?.groups?.get(1)?.value?.toFloatOrNull()
|
||||||
|
userRatings = RATING_USERS_REGEX.find(ratingString)?.groups?.get(1)?.value?.toLongOrNull()
|
||||||
|
favorites = RATING_FAVORITES_REGEX.find(ratingString)?.groups?.get(1)?.value?.toLongOrNull()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input.getElementById("Category")?.children()?.first()?.text()?.let {
|
input.getElementById("Category")?.children()?.first()?.text()?.let {
|
||||||
@ -133,5 +141,12 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TM_DATE_FORMAT = SimpleDateFormat("yyyy MMM dd", Locale.US)
|
val TM_DATE_FORMAT = SimpleDateFormat("yyyy MMM dd", Locale.US)
|
||||||
|
val RATING_FLOAT_REGEX = "([0-9].*) \\(".toRegex()
|
||||||
|
val RATING_USERS_REGEX = "\\(([0-9].*) users".toRegex()
|
||||||
|
val RATING_FAVORITES_REGEX = "/ ([0-9].*) favs".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescriptionAdapter(controller: MangaController): TsuminoDescriptionAdapter {
|
||||||
|
return TsuminoDescriptionAdapter(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ import eu.kanade.tachiyomi.source.LocalSource
|
|||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource.Companion.getLewdSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
import eu.kanade.tachiyomi.ui.base.controller.FabController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
@ -56,7 +56,9 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
|
|||||||
import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog
|
import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog
|
import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter
|
import eu.kanade.tachiyomi.ui.manga.chapter.MangaChaptersHeaderAdapter
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoButtonsAdapter
|
||||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
|
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoHeaderAdapter
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoItemAdapter
|
||||||
import eu.kanade.tachiyomi.ui.manga.track.TrackController
|
import eu.kanade.tachiyomi.ui.manga.track.TrackController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||||
@ -71,7 +73,6 @@ import eu.kanade.tachiyomi.util.view.snack
|
|||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.source.EnhancedHttpSource
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
@ -133,6 +134,9 @@ class MangaController :
|
|||||||
private val coverCache: CoverCache by injectLazy()
|
private val coverCache: CoverCache by injectLazy()
|
||||||
|
|
||||||
private var mangaInfoAdapter: MangaInfoHeaderAdapter? = null
|
private var mangaInfoAdapter: MangaInfoHeaderAdapter? = null
|
||||||
|
private var mangaInfoItemAdapter: MangaInfoItemAdapter? = null
|
||||||
|
private var mangaInfoButtonsAdapter: MangaInfoButtonsAdapter? = null
|
||||||
|
private var mangaMetaInfoAdapter: RecyclerView.Adapter<*>? = null
|
||||||
private var chaptersHeaderAdapter: MangaChaptersHeaderAdapter? = null
|
private var chaptersHeaderAdapter: MangaChaptersHeaderAdapter? = null
|
||||||
private var chaptersAdapter: ChaptersAdapter? = null
|
private var chaptersAdapter: ChaptersAdapter? = null
|
||||||
|
|
||||||
@ -201,13 +205,35 @@ class MangaController :
|
|||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
|
|
||||||
if (manga == null || source == null) return
|
if (manga == null || source == null) return
|
||||||
|
val adapters: MutableList<RecyclerView.Adapter<out RecyclerView.ViewHolder>?> = mutableListOf()
|
||||||
|
|
||||||
// Init RecyclerView and adapter
|
// Init RecyclerView and adapter
|
||||||
mangaInfoAdapter = MangaInfoHeaderAdapter(this, fromSource)
|
mangaInfoAdapter = MangaInfoHeaderAdapter(this)
|
||||||
|
|
||||||
|
adapters += mangaInfoAdapter
|
||||||
|
|
||||||
|
val thisSourceAsLewdSource = presenter.source.getLewdSource()
|
||||||
|
if (thisSourceAsLewdSource != null) {
|
||||||
|
mangaMetaInfoAdapter = thisSourceAsLewdSource.getDescriptionAdapter(this)
|
||||||
|
mangaMetaInfoAdapter?.let { adapters += it }
|
||||||
|
}
|
||||||
|
mangaInfoItemAdapter = MangaInfoItemAdapter(this, fromSource)
|
||||||
|
adapters += mangaInfoItemAdapter
|
||||||
|
|
||||||
|
if (!preferences.recommendsInOverflow().get() || smartSearchConfig != null) {
|
||||||
|
mangaInfoButtonsAdapter = MangaInfoButtonsAdapter(this)
|
||||||
|
adapters += mangaInfoButtonsAdapter
|
||||||
|
}
|
||||||
|
|
||||||
chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this)
|
chaptersHeaderAdapter = MangaChaptersHeaderAdapter(this)
|
||||||
|
|
||||||
|
adapters += chaptersHeaderAdapter
|
||||||
|
|
||||||
chaptersAdapter = ChaptersAdapter(this, view.context)
|
chaptersAdapter = ChaptersAdapter(this, view.context)
|
||||||
|
|
||||||
binding.recycler.adapter = ConcatAdapter(mangaInfoAdapter, chaptersHeaderAdapter, chaptersAdapter)
|
adapters += chaptersAdapter
|
||||||
|
|
||||||
|
binding.recycler.adapter = ConcatAdapter(adapters)
|
||||||
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
binding.recycler.layoutManager = LinearLayoutManager(view.context)
|
||||||
binding.recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
binding.recycler.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
||||||
binding.recycler.setHasFixedSize(true)
|
binding.recycler.setHasFixedSize(true)
|
||||||
@ -360,11 +386,11 @@ class MangaController :
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun onNextMetaInfo(flatMetadata: FlatMetadata) {
|
fun onNextMetaInfo(flatMetadata: FlatMetadata) {
|
||||||
presenter.meta = if (presenter.source is LewdSource<*, *>) {
|
val thisSourceAsLewdSource = presenter.source.getLewdSource()
|
||||||
flatMetadata.raise((presenter.source as LewdSource<*, *>).metaClass)
|
if (thisSourceAsLewdSource != null) {
|
||||||
} else if (presenter.source is EnhancedHttpSource && (presenter.source as EnhancedHttpSource).enhancedSource is LewdSource<*, *>) {
|
presenter.meta = flatMetadata.raise(thisSourceAsLewdSource.metaClass)
|
||||||
flatMetadata.raise(((presenter.source as EnhancedHttpSource).enhancedSource as LewdSource<*, *>).metaClass)
|
mangaMetaInfoAdapter?.notifyDataSetChanged()
|
||||||
} else null
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
@ -379,7 +405,8 @@ class MangaController :
|
|||||||
fun onNextMangaInfo(manga: Manga, source: Source /* SY --> */, meta: RaisedSearchMetadata? /* SY <-- */) {
|
fun onNextMangaInfo(manga: Manga, source: Source /* SY --> */, meta: RaisedSearchMetadata? /* SY <-- */) {
|
||||||
if (manga.initialized) {
|
if (manga.initialized) {
|
||||||
// Update view.
|
// Update view.
|
||||||
mangaInfoAdapter?.update(manga, source /* SY --> */, meta /* SY <-- */)
|
mangaInfoAdapter?.update(manga, source)
|
||||||
|
mangaInfoItemAdapter?.update(manga, source, presenter.meta)
|
||||||
} else {
|
} else {
|
||||||
// Initialize manga.
|
// Initialize manga.
|
||||||
fetchMangaInfoFromSource()
|
fetchMangaInfoFromSource()
|
||||||
|
@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.online.LewdSource
|
import eu.kanade.tachiyomi.source.online.LewdSource
|
||||||
|
import eu.kanade.tachiyomi.source.online.LewdSource.Companion.isLewdSource
|
||||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||||
@ -116,7 +117,7 @@ class MangaPresenter(
|
|||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (manga.initialized && (source is LewdSource<*, *> || (source is EnhancedHttpSource && source.enhancedSource is LewdSource<*, *>))) {
|
if (manga.initialized && source.isLewdSource()) {
|
||||||
getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else Timber.d("Invalid metadata") })
|
getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else Timber.d("Invalid metadata") })
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga.info
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.databinding.MangaInfoButtonsBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class MangaInfoButtonsAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<MangaInfoButtonsAdapter.HeaderViewHolder>() {
|
||||||
|
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: MangaInfoButtonsBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
|
||||||
|
binding = MangaInfoButtonsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return HeaderViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
// EXH -->
|
||||||
|
if (controller.smartSearchConfig == null) {
|
||||||
|
binding.recommendBtn.visibleIf { !preferences.recommendsInOverflow().get() }
|
||||||
|
binding.recommendBtn.clicks()
|
||||||
|
.onEach { controller.openRecommends() }
|
||||||
|
.launchIn(scope)
|
||||||
|
} else {
|
||||||
|
if (controller.smartSearchConfig.origMangaId != null) {
|
||||||
|
binding.mergeBtn.visible()
|
||||||
|
}
|
||||||
|
binding.mergeBtn.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.mergeWithAnother()
|
||||||
|
}
|
||||||
|
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
// EXH <--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,17 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga.info
|
package eu.kanade.tachiyomi.ui.manga.info
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.data.glide.MangaThumbnail
|
import eu.kanade.tachiyomi.data.glide.MangaThumbnail
|
||||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.databinding.MangaInfoHeaderBinding
|
import eu.kanade.tachiyomi.databinding.MangaInfoHeaderBinding
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
@ -29,44 +23,30 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard
|
|||||||
import eu.kanade.tachiyomi.util.view.gone
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
import eu.kanade.tachiyomi.util.view.setTooltip
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
|
||||||
import exh.MERGED_SOURCE_ID
|
import exh.MERGED_SOURCE_ID
|
||||||
import exh.isNamespaceSource
|
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
|
||||||
import exh.util.SourceTagsUtil
|
import exh.util.SourceTagsUtil
|
||||||
import exh.util.makeSearchChip
|
|
||||||
import exh.util.setChipsExtended
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.merge
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import reactivecircus.flowbinding.android.view.longClicks
|
import reactivecircus.flowbinding.android.view.longClicks
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class MangaInfoHeaderAdapter(
|
class MangaInfoHeaderAdapter(
|
||||||
private val controller: MangaController,
|
private val controller: MangaController
|
||||||
private val fromSource: Boolean
|
|
||||||
) :
|
) :
|
||||||
RecyclerView.Adapter<MangaInfoHeaderAdapter.HeaderViewHolder>() {
|
RecyclerView.Adapter<MangaInfoHeaderAdapter.HeaderViewHolder>() {
|
||||||
|
|
||||||
private var manga: Manga = controller.presenter.manga
|
private var manga: Manga = controller.presenter.manga
|
||||||
private var source: Source = controller.presenter.source
|
private var source: Source = controller.presenter.source
|
||||||
private var trackCount: Int = 0
|
private var trackCount: Int = 0
|
||||||
// SY -->
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
private var meta: RaisedSearchMetadata? = controller.presenter.meta
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
private lateinit var binding: MangaInfoHeaderBinding
|
private lateinit var binding: MangaInfoHeaderBinding
|
||||||
|
|
||||||
private var initialLoad: Boolean = true
|
|
||||||
private var currentMangaThumbnail: MangaThumbnail? = null
|
private var currentMangaThumbnail: MangaThumbnail? = null
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
|
||||||
@ -80,18 +60,15 @@ class MangaInfoHeaderAdapter(
|
|||||||
holder.bind()
|
holder.bind()
|
||||||
}
|
}
|
||||||
|
|
||||||
val tagsAdapter: FlexibleAdapter<IFlexible<*>> = FlexibleAdapter(null)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the view with manga information.
|
* Update the view with manga information.
|
||||||
*
|
*
|
||||||
* @param manga manga object containing information about manga.
|
* @param manga manga object containing information about manga.
|
||||||
* @param source the source of the manga.
|
* @param source the source of the manga.
|
||||||
*/
|
*/
|
||||||
fun update(manga: Manga, source: Source, meta: RaisedSearchMetadata?) {
|
fun update(manga: Manga, source: Source) {
|
||||||
this.manga = manga
|
this.manga = manga
|
||||||
this.source = source
|
this.source = source
|
||||||
this.meta = meta
|
|
||||||
|
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
@ -226,15 +203,6 @@ class MangaInfoHeaderAdapter(
|
|||||||
}
|
}
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
binding.mangaSummary.longClicks()
|
|
||||||
.onEach {
|
|
||||||
controller.activity?.copyToClipboard(
|
|
||||||
view.context.getString(R.string.description),
|
|
||||||
binding.mangaSummary.text.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.launchIn(scope)
|
|
||||||
|
|
||||||
binding.mangaCover.longClicks()
|
binding.mangaCover.longClicks()
|
||||||
.onEach {
|
.onEach {
|
||||||
controller.activity?.copyToClipboard(
|
controller.activity?.copyToClipboard(
|
||||||
@ -244,28 +212,6 @@ class MangaInfoHeaderAdapter(
|
|||||||
}
|
}
|
||||||
.launchIn(scope)
|
.launchIn(scope)
|
||||||
|
|
||||||
// EXH -->
|
|
||||||
if (controller.smartSearchConfig == null) {
|
|
||||||
binding.recommendBtn.visibleIf { !preferences.recommendsInOverflow().get() }
|
|
||||||
binding.recommendBtn.clicks()
|
|
||||||
.onEach { controller.openRecommends() }
|
|
||||||
.launchIn(scope)
|
|
||||||
} else {
|
|
||||||
if (controller.smartSearchConfig.origMangaId != null) { binding.mergeBtn.visible() }
|
|
||||||
binding.mergeBtn.clicks()
|
|
||||||
.onEach {
|
|
||||||
controller.mergeWithAnother()
|
|
||||||
}
|
|
||||||
|
|
||||||
.launchIn(scope)
|
|
||||||
}
|
|
||||||
// EXH <--
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
binding.mangaNamespaceTagsRecycler.layoutManager = LinearLayoutManager(itemView.context)
|
|
||||||
binding.mangaNamespaceTagsRecycler.adapter = tagsAdapter
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
setMangaInfo(manga, source)
|
setMangaInfo(manga, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +221,6 @@ class MangaInfoHeaderAdapter(
|
|||||||
* @param manga manga object containing information about manga.
|
* @param manga manga object containing information about manga.
|
||||||
* @param source the source of the manga.
|
* @param source the source of the manga.
|
||||||
*/
|
*/
|
||||||
@ExperimentalCoroutinesApi
|
|
||||||
private fun setMangaInfo(manga: Manga, source: Source?) {
|
private fun setMangaInfo(manga: Manga, source: Source?) {
|
||||||
// Update full title TextView.
|
// Update full title TextView.
|
||||||
binding.mangaFullTitle.text = if (manga.title.isBlank()) {
|
binding.mangaFullTitle.text = if (manga.title.isBlank()) {
|
||||||
@ -343,100 +288,6 @@ class MangaInfoHeaderAdapter(
|
|||||||
.into(it)
|
.into(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manga info section
|
|
||||||
val hasInfoContent = !manga.description.isNullOrBlank() || !manga.genre.isNullOrBlank()
|
|
||||||
showMangaInfo(hasInfoContent)
|
|
||||||
if (hasInfoContent) {
|
|
||||||
// Update description TextView.
|
|
||||||
binding.mangaSummary.text = if (manga.description.isNullOrBlank()) {
|
|
||||||
view.context.getString(R.string.unknown)
|
|
||||||
} else {
|
|
||||||
manga.description
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update genres list
|
|
||||||
if (!manga.genre.isNullOrBlank()) {
|
|
||||||
// SY -->
|
|
||||||
if (source != null && source.isNamespaceSource()) {
|
|
||||||
val genre = manga.getGenres()
|
|
||||||
if (!genre.isNullOrEmpty()) {
|
|
||||||
val namespaceTags = genre.map { SourceTagsUtil().parseTag(it) }
|
|
||||||
.groupBy { it.first }
|
|
||||||
.mapValues { values -> values.value.map { makeSearchChip(it.second, controller::performSearch, controller::performGlobalSearch, source.id, itemView.context, it.first) } }
|
|
||||||
.map { NamespaceTagsItem(it.key, it.value) }
|
|
||||||
tagsAdapter.updateDataSet(namespaceTags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.mangaGenresTagsFullChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
|
||||||
binding.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
|
||||||
// SY <--
|
|
||||||
} else {
|
|
||||||
binding.mangaGenresTagsWrapper.gone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle showing more or less info
|
|
||||||
merge(view.clicks(), binding.mangaSummary.clicks(), binding.mangaInfoToggle.clicks())
|
|
||||||
.onEach { toggleMangaInfo(view.context) }
|
|
||||||
.launchIn(scope)
|
|
||||||
|
|
||||||
// Expand manga info if navigated from source listing
|
|
||||||
if (initialLoad && fromSource) {
|
|
||||||
toggleMangaInfo(view.context)
|
|
||||||
initialLoad = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showMangaInfo(visible: Boolean) {
|
|
||||||
binding.mangaSummaryLabel.visibleIf { visible }
|
|
||||||
binding.mangaSummary.visibleIf { visible }
|
|
||||||
binding.mangaGenresTagsWrapper.visibleIf { visible }
|
|
||||||
binding.mangaInfoToggle.visibleIf { visible }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun toggleMangaInfo(context: Context) {
|
|
||||||
val isExpanded =
|
|
||||||
binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
|
||||||
|
|
||||||
with(binding.mangaInfoToggle) {
|
|
||||||
text = if (isExpanded) {
|
|
||||||
context.getString(R.string.manga_info_expand)
|
|
||||||
} else {
|
|
||||||
context.getString(R.string.manga_info_collapse)
|
|
||||||
}
|
|
||||||
|
|
||||||
icon = if (isExpanded) {
|
|
||||||
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
|
||||||
} else {
|
|
||||||
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
with(binding.mangaSummary) {
|
|
||||||
maxLines =
|
|
||||||
if (isExpanded) {
|
|
||||||
2
|
|
||||||
} else {
|
|
||||||
Int.MAX_VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
ellipsize =
|
|
||||||
if (isExpanded) {
|
|
||||||
TextUtils.TruncateAt.END
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
|
||||||
// SY -->
|
|
||||||
if (source.isNamespaceSource()) {
|
|
||||||
binding.mangaNamespaceTagsRecycler.visibleIf { !isExpanded }
|
|
||||||
} else {
|
|
||||||
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,214 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga.info
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.databinding.MangaInfoItemBinding
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
|
import exh.isEhBasedSource
|
||||||
|
import exh.isNamespaceSource
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL
|
||||||
|
import exh.util.SourceTagsUtil
|
||||||
|
import exh.util.makeSearchChip
|
||||||
|
import exh.util.setChipsExtended
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.merge
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
import reactivecircus.flowbinding.android.view.longClicks
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class MangaInfoItemAdapter(
|
||||||
|
private val controller: MangaController,
|
||||||
|
private val fromSource: Boolean
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<MangaInfoItemAdapter.HeaderViewHolder>() {
|
||||||
|
|
||||||
|
private var manga: Manga = controller.presenter.manga
|
||||||
|
private var source: Source = controller.presenter.source
|
||||||
|
private var meta: RaisedSearchMetadata? = controller.presenter.meta
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: MangaInfoItemBinding
|
||||||
|
|
||||||
|
private var initialLoad: Boolean = true
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
|
||||||
|
binding = MangaInfoItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return HeaderViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mangaTagsInfoAdapter: FlexibleAdapter<IFlexible<*>>? = FlexibleAdapter(null)
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the view with manga information.
|
||||||
|
*
|
||||||
|
* @param manga manga object containing information about manga.
|
||||||
|
* @param source the source of the manga.
|
||||||
|
*/
|
||||||
|
fun update(manga: Manga, source: Source, meta: RaisedSearchMetadata?) {
|
||||||
|
this.manga = manga
|
||||||
|
this.source = source
|
||||||
|
this.meta = meta
|
||||||
|
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
binding.mangaSummary.longClicks()
|
||||||
|
.onEach {
|
||||||
|
controller.activity?.copyToClipboard(
|
||||||
|
view.context.getString(R.string.description),
|
||||||
|
binding.mangaSummary.text.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
|
||||||
|
binding.genreGroups.layoutManager = LinearLayoutManager(itemView.context)
|
||||||
|
binding.genreGroups.adapter = mangaTagsInfoAdapter
|
||||||
|
|
||||||
|
setMangaInfo(manga, source)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the view with manga information.
|
||||||
|
*
|
||||||
|
* @param manga manga object containing information about manga.
|
||||||
|
* @param source the source of the manga.
|
||||||
|
*/
|
||||||
|
@ExperimentalCoroutinesApi
|
||||||
|
private fun setMangaInfo(manga: Manga, source: Source?) {
|
||||||
|
// Manga info section
|
||||||
|
val hasInfoContent = !manga.description.isNullOrBlank() || !manga.genre.isNullOrBlank()
|
||||||
|
showMangaInfo(hasInfoContent)
|
||||||
|
if (hasInfoContent) {
|
||||||
|
// Update description TextView.
|
||||||
|
binding.mangaSummary.text = if (manga.description.isNullOrBlank()) {
|
||||||
|
view.context.getString(R.string.unknown)
|
||||||
|
} else {
|
||||||
|
manga.description
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding.mangaSummary.text == "meta") {
|
||||||
|
binding.mangaSummary.gone()
|
||||||
|
binding.mangaSummaryLabel.setText(R.string.tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update genres list
|
||||||
|
if (!manga.genre.isNullOrBlank()) {
|
||||||
|
// SY -->
|
||||||
|
if (source != null && source.isNamespaceSource()) {
|
||||||
|
val metaTags = meta?.tags?.filterNot { it.type == TAG_TYPE_VIRTUAL }?.groupBy { it.namespace }
|
||||||
|
var namespaceTags: List<NamespaceTagsItem> = emptyList()
|
||||||
|
if (source.isEhBasedSource() && metaTags != null && metaTags.all { it.key != null }) {
|
||||||
|
namespaceTags = metaTags
|
||||||
|
.mapValues { values -> values.value.map { makeSearchChip(it.name, controller::performSearch, controller::performGlobalSearch, source.id, itemView.context, it.namespace, it.type) } }
|
||||||
|
.map { NamespaceTagsItem(it.key!!, it.value) }
|
||||||
|
} else {
|
||||||
|
val genre = manga.getGenres()
|
||||||
|
if (!genre.isNullOrEmpty()) {
|
||||||
|
namespaceTags = genre.map { SourceTagsUtil().parseTag(it) }
|
||||||
|
.groupBy { it.first }
|
||||||
|
.mapValues { values -> values.value.map { makeSearchChip(it.second, controller::performSearch, controller::performGlobalSearch, source.id, itemView.context, it.first) } }
|
||||||
|
.map { NamespaceTagsItem(it.key, it.value) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mangaTagsInfoAdapter?.updateDataSet(namespaceTags)
|
||||||
|
}
|
||||||
|
binding.mangaGenresTagsFullChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
||||||
|
binding.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
||||||
|
// SY <--
|
||||||
|
} else {
|
||||||
|
binding.mangaGenresTagsWrapper.gone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle showing more or less info
|
||||||
|
merge(view.clicks(), binding.mangaSummary.clicks(), binding.mangaInfoToggle.clicks())
|
||||||
|
.onEach { toggleMangaInfo(view.context) }
|
||||||
|
.launchIn(scope)
|
||||||
|
|
||||||
|
// Expand manga info if navigated from source listing
|
||||||
|
if (initialLoad && fromSource) {
|
||||||
|
toggleMangaInfo(view.context)
|
||||||
|
initialLoad = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showMangaInfo(visible: Boolean) {
|
||||||
|
binding.mangaSummaryLabel.visibleIf { visible }
|
||||||
|
binding.mangaSummary.visibleIf { visible }
|
||||||
|
binding.mangaGenresTagsWrapper.visibleIf { visible }
|
||||||
|
binding.mangaInfoToggle.visibleIf { visible }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleMangaInfo(context: Context) {
|
||||||
|
val isExpanded =
|
||||||
|
binding.mangaInfoToggle.text == context.getString(R.string.manga_info_collapse)
|
||||||
|
|
||||||
|
with(binding.mangaInfoToggle) {
|
||||||
|
text = if (isExpanded) {
|
||||||
|
context.getString(R.string.manga_info_expand)
|
||||||
|
} else {
|
||||||
|
context.getString(R.string.manga_info_collapse)
|
||||||
|
}
|
||||||
|
|
||||||
|
icon = if (isExpanded) {
|
||||||
|
context.getDrawable(R.drawable.ic_baseline_expand_more_24dp)
|
||||||
|
} else {
|
||||||
|
context.getDrawable(R.drawable.ic_baseline_expand_less_24dp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with(binding.mangaSummary) {
|
||||||
|
maxLines =
|
||||||
|
if (isExpanded) {
|
||||||
|
2
|
||||||
|
} else {
|
||||||
|
Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
ellipsize =
|
||||||
|
if (isExpanded) {
|
||||||
|
TextUtils.TruncateAt.END
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
||||||
|
// SY -->
|
||||||
|
if (!source.isNamespaceSource()) {
|
||||||
|
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
||||||
|
} else {
|
||||||
|
binding.genreGroups.visibleIf { !isExpanded }
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -58,4 +58,4 @@ fun isLewdSource(source: Long) = source in 6900..6999 ||
|
|||||||
|
|
||||||
fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID
|
fun Source.isEhBasedSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID
|
||||||
|
|
||||||
fun Source.isNamespaceSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID || id == NHENTAI_SOURCE_ID || id == HITOMI_SOURCE_ID || id == PURURIN_SOURCE_ID || id == TSUMINO_SOURCE_ID
|
fun Source.isNamespaceSource() = id == EH_SOURCE_ID || id == EXH_SOURCE_ID || id == NHENTAI_SOURCE_ID || id == HITOMI_SOURCE_ID || id == PURURIN_SOURCE_ID || id == TSUMINO_SOURCE_ID || id == EIGHTMUSES_SOURCE_ID || id == HBROWSE_SOURCE_ID
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
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.ONGOING_SUFFIX
|
import exh.metadata.ONGOING_SUFFIX
|
||||||
import exh.metadata.humanReadableByteCount
|
import exh.metadata.humanReadableByteCount
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -76,7 +77,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build a nice looking description out of what we know
|
// Build a nice looking description out of what we know
|
||||||
val titleDesc = StringBuilder()
|
/* val titleDesc = StringBuilder()
|
||||||
title?.let { titleDesc += "Title: $it\n" }
|
title?.let { titleDesc += "Title: $it\n" }
|
||||||
altTitle?.let { titleDesc += "Alternate Title: $it\n" }
|
altTitle?.let { titleDesc += "Alternate Title: $it\n" }
|
||||||
|
|
||||||
@ -99,11 +100,36 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
detailsDesc += "\n"
|
detailsDesc += "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
gId?.let { pairs += Pair(context.getString(R.string.id), it) }
|
||||||
|
gToken?.let { pairs += Pair(context.getString(R.string.token), it) }
|
||||||
|
exh?.let { pairs += Pair(context.getString(R.string.is_exhentai_gallery), context.getString(if (it) android.R.string.yes else android.R.string.no)) }
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
altTitle?.let { pairs += Pair(context.getString(R.string.alt_title), it) }
|
||||||
|
genre?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
|
datePosted?.let { pairs += Pair(context.getString(R.string.date_posted), EX_DATE_FORMAT.format(Date(it))) }
|
||||||
|
parent?.let { pairs += Pair(context.getString(R.string.parent), it) }
|
||||||
|
visible?.let { pairs += Pair(context.getString(R.string.visible), it) }
|
||||||
|
language?.let { pairs += Pair(context.getString(R.string.language), it) }
|
||||||
|
translated?.let { pairs += Pair("Translated", context.getString(if (it) android.R.string.yes else android.R.string.no)) }
|
||||||
|
size?.let { pairs += Pair(context.getString(R.string.gallery_size), humanReadableByteCount(it, true)) }
|
||||||
|
length?.let { pairs += Pair(context.getString(R.string.page_count), it.toString()) }
|
||||||
|
favorites?.let { pairs += Pair(context.getString(R.string.total_favorites), it.toString()) }
|
||||||
|
ratingCount?.let { pairs += Pair(context.getString(R.string.total_ratings), it.toString()) }
|
||||||
|
averageRating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
||||||
|
aged.let { pairs += Pair(context.getString(R.string.aged), context.getString(if (it) android.R.string.yes else android.R.string.no)) }
|
||||||
|
lastUpdateCheck.let { pairs += Pair(context.getString(R.string.last_update_check), EX_DATE_FORMAT.format(Date(it))) }
|
||||||
|
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -112,6 +138,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
const val TAG_TYPE_NORMAL = 0
|
const val TAG_TYPE_NORMAL = 0
|
||||||
const val TAG_TYPE_LIGHT = 1
|
const val TAG_TYPE_LIGHT = 1
|
||||||
|
const val TAG_TYPE_WEAK = 2
|
||||||
|
|
||||||
const val EH_GENRE_NAMESPACE = "genre"
|
const val EH_GENRE_NAMESPACE = "genre"
|
||||||
private const val EH_ARTIST_NAMESPACE = "artist"
|
private const val EH_ARTIST_NAMESPACE = "artist"
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
|
||||||
|
|
||||||
class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
||||||
var path: List<String> = emptyList()
|
var path: List<String> = emptyList()
|
||||||
@ -26,14 +27,25 @@ class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
manga.genre = tagsToGenreString()
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
/*val titleDesc = StringBuilder()
|
||||||
title?.let { titleDesc += "Title: $it\n" }
|
title?.let { titleDesc += "Title: $it\n" }
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
val path = path.joinToString("/", prefix = "/")
|
||||||
|
if (path.isNotBlank()) {
|
||||||
|
pairs += Pair(context.getString(R.string.path), path)
|
||||||
|
}
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.EightMusesSearchMetadata.Companion.ARTIST_NAMESPACE
|
import exh.metadata.metadata.EightMusesSearchMetadata.Companion.ARTIST_NAMESPACE
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
|
||||||
|
|
||||||
class HBrowseSearchMetadata : RaisedSearchMetadata() {
|
class HBrowseSearchMetadata : RaisedSearchMetadata() {
|
||||||
var hbId: Long? = null
|
var hbId: Long? = null
|
||||||
@ -27,15 +28,25 @@ class HBrowseSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
manga.artist = tags.ofNamespace(ARTIST_NAMESPACE).joinToString { it.name }
|
manga.artist = tags.ofNamespace(ARTIST_NAMESPACE).joinToString { it.name }
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
|
/*val titleDesc = StringBuilder()
|
||||||
title?.let { titleDesc += "Title: $it\n" }
|
title?.let { titleDesc += "Title: $it\n" }
|
||||||
length?.let { titleDesc += "Length: $it page(s)\n" }
|
length?.let { titleDesc += "Length: $it page(s)\n" }
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
hbId?.let { pairs += Pair(context.getString(R.string.id), it.toString()) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
length?.let { pairs += Pair(context.getString(R.string.page_count), it.toString()) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
|
||||||
@ -30,16 +32,26 @@ class HentaiCafeSearchMetadata : RaisedSearchMetadata() {
|
|||||||
// Not available
|
// Not available
|
||||||
manga.status = SManga.UNKNOWN
|
manga.status = SManga.UNKNOWN
|
||||||
|
|
||||||
val detailsDesc = "Title: $title\n" +
|
|
||||||
"Artist: $artist\n"
|
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
|
||||||
|
|
||||||
manga.genre = tagsToGenreString()
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
manga.description = listOf(detailsDesc, tagsDesc.toString())
|
/* val detailsDesc = "Title: $title\n" +
|
||||||
|
"Artist: $artist\n"
|
||||||
|
|
||||||
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
|
manga.description = "meta" /*listOf(detailsDesc, tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
hcId?.let { pairs += Pair(context.getString(R.string.id), it) }
|
||||||
|
readerId?.let { pairs += Pair(context.getString(R.string.reader_id), it) }
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
artist?.let { pairs += Pair(context.getString(R.string.artist), it) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
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.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
@ -37,17 +39,25 @@ class HitomiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
override fun copyTo(manga: SManga) {
|
override fun copyTo(manga: SManga) {
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
thumbnailUrl?.let { manga.thumbnail_url = it }
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
|
|
||||||
title?.let {
|
title?.let {
|
||||||
manga.title = it
|
manga.title = it
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy tags -> genres
|
||||||
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
|
manga.artist = artists.joinToString()
|
||||||
|
|
||||||
|
manga.status = SManga.UNKNOWN
|
||||||
|
|
||||||
|
/*val titleDesc = StringBuilder()
|
||||||
|
|
||||||
|
title?.let {
|
||||||
titleDesc += "Title: $it\n"
|
titleDesc += "Title: $it\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
val detailsDesc = StringBuilder()
|
||||||
|
|
||||||
manga.artist = artists.joinToString()
|
|
||||||
|
|
||||||
detailsDesc += "Artist(s): ${manga.artist}\n"
|
detailsDesc += "Artist(s): ${manga.artist}\n"
|
||||||
|
|
||||||
group?.let {
|
group?.let {
|
||||||
@ -74,16 +84,35 @@ class HitomiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
detailsDesc += "Upload date: ${EX_DATE_FORMAT.format(Date(it))}\n"
|
detailsDesc += "Upload date: ${EX_DATE_FORMAT.format(Date(it))}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
manga.status = SManga.UNKNOWN
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
// Copy tags -> genres
|
manga.description = "meta" /*listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
||||||
manga.genre = tagsToGenreString()
|
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
hlId?.let { pairs += Pair(context.getString(R.string.id), it) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
val artists = artists.joinToString()
|
||||||
|
if (artists.isNotBlank()) {
|
||||||
|
pairs += Pair(context.getString(R.string.artist), artists)
|
||||||
|
}
|
||||||
|
group?.let { pairs += Pair(context.getString(R.string.group), it) }
|
||||||
|
type?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
|
language?.let { pairs += Pair(context.getString(R.string.language), it) }
|
||||||
|
val series = series.joinToString()
|
||||||
|
if (series.isNotBlank()) {
|
||||||
|
pairs += Pair(context.getString(R.string.series), series)
|
||||||
|
}
|
||||||
|
val characters = characters.joinToString()
|
||||||
|
if (characters.isNotBlank()) {
|
||||||
|
pairs += Pair(context.getString(R.string.characters), characters)
|
||||||
|
}
|
||||||
|
uploadDate?.let { pairs += Pair(context.getString(R.string.date_posted), EX_DATE_FORMAT.format(Date(it))) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
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.ONGOING_SUFFIX
|
import exh.metadata.ONGOING_SUFFIX
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.nullIfBlank
|
|
||||||
import exh.plusAssign
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -77,7 +77,7 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
/*val titleDesc = StringBuilder()
|
||||||
englishTitle?.let { titleDesc += "English Title: $it\n" }
|
englishTitle?.let { titleDesc += "English Title: $it\n" }
|
||||||
japaneseTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
japaneseTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
||||||
shortTitle?.let { titleDesc += "Short Title: $it\n" }
|
shortTitle?.let { titleDesc += "Short Title: $it\n" }
|
||||||
@ -89,11 +89,27 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
favoritesCount?.let { detailsDesc += "Favorited: $it times\n" }
|
favoritesCount?.let { detailsDesc += "Favorited: $it times\n" }
|
||||||
scanlator?.nullIfBlank()?.let { detailsDesc += "Scanlator: $it\n" }
|
scanlator?.nullIfBlank()?.let { detailsDesc += "Scanlator: $it\n" }
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
nhId?.let { pairs += Pair(context.getString(R.string.id), it.toString()) }
|
||||||
|
uploadDate?.let { pairs += Pair(context.getString(R.string.date_posted), EX_DATE_FORMAT.format(Date(it * 1000))) }
|
||||||
|
favoritesCount?.let { pairs += Pair(context.getString(R.string.total_favorites), it.toString()) }
|
||||||
|
mediaId?.let { pairs += Pair(context.getString(R.string.media_id), it) }
|
||||||
|
japaneseTitle?.let { pairs += Pair(context.getString(R.string.japanese_title), it) }
|
||||||
|
englishTitle?.let { pairs += Pair(context.getString(R.string.english_title), it) }
|
||||||
|
shortTitle?.let { pairs += Pair(context.getString(R.string.short_title), it) }
|
||||||
|
coverImageType?.let { pairs += Pair(context.getString(R.string.cover_image_file_type), it) }
|
||||||
|
pageImageTypes.size.let { pairs += Pair(context.getString(R.string.page_count), it.toString()) }
|
||||||
|
thumbnailImageType?.let { pairs += Pair(context.getString(R.string.thumbnail_image_file_type), it) }
|
||||||
|
scanlator?.let { pairs += Pair(context.getString(R.string.scanlator), it) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -106,7 +122,7 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
const val BASE_URL = "https://nhentai.net"
|
const val BASE_URL = "https://nhentai.net"
|
||||||
|
|
||||||
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
|
private const val NHENTAI_ARTIST_NAMESPACE = "artist"
|
||||||
private const val NHENTAI_CATEGORIES_NAMESPACE = "category"
|
const val NHENTAI_CATEGORIES_NAMESPACE = "category"
|
||||||
|
|
||||||
fun typeToExtension(t: String?) =
|
fun typeToExtension(t: String?) =
|
||||||
when (t) {
|
when (t) {
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
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.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedTitle
|
import exh.metadata.metadata.base.RaisedTitle
|
||||||
import exh.plusAssign
|
|
||||||
|
|
||||||
class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
||||||
var pvId: String? = null
|
var pvId: String? = null
|
||||||
@ -36,9 +37,28 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
url?.let { manga.url = it }
|
url?.let { manga.url = it }
|
||||||
thumbnailUrl?.let { manga.thumbnail_url = it }
|
thumbnailUrl?.let { manga.thumbnail_url = it }
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
|
||||||
title?.let {
|
title?.let {
|
||||||
manga.title = it
|
manga.title = it
|
||||||
|
}
|
||||||
|
|
||||||
|
artist?.let {
|
||||||
|
manga.artist = it
|
||||||
|
}
|
||||||
|
|
||||||
|
status?.let {
|
||||||
|
manga.status = when (it) {
|
||||||
|
"Ongoing" -> SManga.ONGOING
|
||||||
|
"Completed", "Suspended" -> SManga.COMPLETED
|
||||||
|
else -> SManga.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy tags -> genres
|
||||||
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
|
/*val titleDesc = StringBuilder()
|
||||||
|
|
||||||
|
title?.let {
|
||||||
titleDesc += "Title: $it\n"
|
titleDesc += "Title: $it\n"
|
||||||
}
|
}
|
||||||
if (altTitles.isNotEmpty()) {
|
if (altTitles.isNotEmpty()) {
|
||||||
@ -50,7 +70,6 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
val detailsDesc = StringBuilder()
|
||||||
artist?.let {
|
artist?.let {
|
||||||
manga.artist = it
|
|
||||||
detailsDesc += "Artist: $it\n"
|
detailsDesc += "Artist: $it\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +78,6 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
status?.let {
|
status?.let {
|
||||||
manga.status = when (it) {
|
|
||||||
"Ongoing" -> SManga.ONGOING
|
|
||||||
"Completed", "Suspended" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
detailsDesc += "Status: $it\n"
|
detailsDesc += "Status: $it\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,14 +85,30 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
detailsDesc += "Rating: %.2\n".format(it)
|
detailsDesc += "Rating: %.2\n".format(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy tags -> genres
|
|
||||||
manga.genre = tagsToGenreString()
|
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
pvId?.let { pairs += Pair(context.getString(R.string.id), it) }
|
||||||
|
url?.let { pairs += Pair(context.getString(R.string.url), it) }
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
val altTitles = altTitles.joinToString()
|
||||||
|
if (altTitles.isNotBlank()) {
|
||||||
|
pairs += Pair(context.getString(R.string.alt_titles), altTitles)
|
||||||
|
}
|
||||||
|
artist?.let { pairs += Pair(context.getString(R.string.artist), it) }
|
||||||
|
type?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
|
rating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
||||||
|
status?.let { pairs += Pair(context.getString(R.string.status), it) }
|
||||||
|
lang?.let { pairs += Pair(context.getString(R.string.language), it) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
|
||||||
|
|
||||||
class PururinSearchMetadata : RaisedSearchMetadata() {
|
class PururinSearchMetadata : RaisedSearchMetadata() {
|
||||||
var prId: Int? = null
|
var prId: Int? = null
|
||||||
@ -42,7 +43,7 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
manga.genre = tagsToGenreString()
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
val titleDesc = StringBuilder()
|
/*val titleDesc = StringBuilder()
|
||||||
title?.let { titleDesc += "English Title: $it\n" }
|
title?.let { titleDesc += "English Title: $it\n" }
|
||||||
altTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
altTitle?.let { titleDesc += "Japanese Title: $it\n" }
|
||||||
|
|
||||||
@ -52,11 +53,26 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
fileSize?.let { detailsDesc += "Size: $it\n" }
|
fileSize?.let { detailsDesc += "Size: $it\n" }
|
||||||
ratingCount?.let { detailsDesc += "Rating: $averageRating ($ratingCount)\n" }
|
ratingCount?.let { detailsDesc += "Rating: $averageRating ($ratingCount)\n" }
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
val tagsDesc = tagsToDescription()*/
|
||||||
|
|
||||||
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
manga.description = "meta" /*listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
prId?.let { pairs += Pair(context.getString(R.string.id), it.toString()) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
altTitle?.let { pairs += Pair(context.getString(R.string.alt_title), it) }
|
||||||
|
thumbnailUrl?.let { pairs += Pair(context.getString(R.string.thumbnail_url), it) }
|
||||||
|
uploaderDisp?.let { pairs += Pair(context.getString(R.string.uploader_capital), it) }
|
||||||
|
uploader?.let { pairs += Pair(context.getString(R.string.uploader), it) }
|
||||||
|
pages?.let { pairs += Pair(context.getString(R.string.page_count), it.toString()) }
|
||||||
|
fileSize?.let { pairs += Pair(context.getString(R.string.gallery_size), it) }
|
||||||
|
ratingCount?.let { pairs += Pair(context.getString(R.string.total_ratings), it.toString()) }
|
||||||
|
averageRating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -66,6 +82,7 @@ class PururinSearchMetadata : RaisedSearchMetadata() {
|
|||||||
const val TAG_TYPE_DEFAULT = 0
|
const val TAG_TYPE_DEFAULT = 0
|
||||||
|
|
||||||
private const val TAG_NAMESPACE_ARTIST = "artist"
|
private const val TAG_NAMESPACE_ARTIST = "artist"
|
||||||
|
const val TAG_NAMESPACE_CATEGORY = "category"
|
||||||
|
|
||||||
val BASE_URL = "https://pururin.io"
|
val BASE_URL = "https://pururin.io"
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package exh.metadata.metadata
|
package exh.metadata.metadata
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
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.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
||||||
var tmId: Int? = null
|
var tmId: Int? = null
|
||||||
@ -20,6 +23,12 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
var ratingString: String? = null
|
var ratingString: String? = null
|
||||||
|
|
||||||
|
var averageRating: Float? = null
|
||||||
|
|
||||||
|
var userRatings: Long? = null
|
||||||
|
|
||||||
|
var favorites: Long? = null
|
||||||
|
|
||||||
var category: String? = null
|
var category: String? = null
|
||||||
|
|
||||||
var collection: String? = null
|
var collection: String? = null
|
||||||
@ -38,7 +47,10 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
manga.status = SManga.UNKNOWN
|
manga.status = SManga.UNKNOWN
|
||||||
|
|
||||||
val titleDesc = "Title: $title\n"
|
// Copy tags -> genres
|
||||||
|
manga.genre = tagsToGenreString()
|
||||||
|
|
||||||
|
/*val titleDesc = "Title: $title\n"
|
||||||
|
|
||||||
val detailsDesc = StringBuilder()
|
val detailsDesc = StringBuilder()
|
||||||
uploader?.let { detailsDesc += "Uploader: $it\n" }
|
uploader?.let { detailsDesc += "Uploader: $it\n" }
|
||||||
@ -59,14 +71,36 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
|||||||
detailsDesc += "Character: $charactersString\n"
|
detailsDesc += "Character: $charactersString\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy tags -> genres
|
val tagsDesc = tagsToDescription()*/
|
||||||
manga.genre = tagsToGenreString()
|
|
||||||
|
|
||||||
val tagsDesc = tagsToDescription()
|
manga.description = "meta" /*listOf(titleDesc, detailsDesc.toString(), tagsDesc.toString())
|
||||||
|
|
||||||
manga.description = listOf(titleDesc, detailsDesc.toString(), tagsDesc.toString())
|
|
||||||
.filter(String::isNotBlank)
|
.filter(String::isNotBlank)
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraInfoPairs(context: Context): List<Pair<String, String>> {
|
||||||
|
val pairs = mutableListOf<Pair<String, String>>()
|
||||||
|
tmId?.let { pairs += Pair(context.getString(R.string.id), it.toString()) }
|
||||||
|
title?.let { pairs += Pair(context.getString(R.string.title), it) }
|
||||||
|
uploader?.let { pairs += Pair(context.getString(R.string.uploader), it) }
|
||||||
|
uploadDate?.let { pairs += Pair(context.getString(R.string.date_posted), EX_DATE_FORMAT.format(Date(it))) }
|
||||||
|
length?.let { pairs += Pair(context.getString(R.string.page_count), it.toString()) }
|
||||||
|
ratingString?.let { pairs += Pair(context.getString(R.string.rating_string), it) }
|
||||||
|
averageRating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
||||||
|
userRatings?.let { pairs += Pair(context.getString(R.string.total_ratings), it.toString()) }
|
||||||
|
favorites?.let { pairs += Pair(context.getString(R.string.total_favorites), it.toString()) }
|
||||||
|
category?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
|
collection?.let { pairs += Pair(context.getString(R.string.collection), it) }
|
||||||
|
group?.let { pairs += Pair(context.getString(R.string.group), it) }
|
||||||
|
val parodiesString = parody.joinToString()
|
||||||
|
if (parodiesString.isNotEmpty()) {
|
||||||
|
pairs += Pair(context.getString(R.string.parodies), parodiesString)
|
||||||
|
}
|
||||||
|
val charactersString = character.joinToString()
|
||||||
|
if (charactersString.isNotEmpty()) {
|
||||||
|
pairs += Pair(context.getString(R.string.characters), charactersString)
|
||||||
|
}
|
||||||
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -76,6 +110,8 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
val BASE_URL = "https://www.tsumino.com"
|
val BASE_URL = "https://www.tsumino.com"
|
||||||
|
|
||||||
|
val TSUMINO_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US)
|
||||||
|
|
||||||
fun tmIdFromUrl(url: String) =
|
fun tmIdFromUrl(url: String) =
|
||||||
Uri.parse(url).lastPathSegment
|
Uri.parse(url).lastPathSegment
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package exh.metadata.metadata.base
|
package exh.metadata.metadata.base
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.forEach
|
import exh.metadata.forEach
|
||||||
@ -112,6 +113,8 @@ abstract class RaisedSearchMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun getExtraInfoPairs(context: Context): List<Pair<String, String>>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Virtual tags allow searching of otherwise unindexed fields
|
// Virtual tags allow searching of otherwise unindexed fields
|
||||||
const val TAG_TYPE_VIRTUAL = -2
|
const val TAG_TYPE_VIRTUAL = -2
|
||||||
|
41
app/src/main/java/exh/ui/metadata/MetadataViewAdapter.kt
Normal file
41
app/src/main/java/exh/ui/metadata/MetadataViewAdapter.kt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package exh.ui.metadata
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.databinding.MetadataViewItemBinding
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
class MetadataViewAdapter(private var data: List<Pair<String, String>>) :
|
||||||
|
RecyclerView.Adapter<MetadataViewAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
private lateinit var binding: MetadataViewItemBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MetadataViewAdapter.ViewHolder {
|
||||||
|
binding = MetadataViewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return ViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(data: List<Pair<String, String>>) {
|
||||||
|
this.data = data
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
// binds the data to the TextView in each cell
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
// total number of cells
|
||||||
|
override fun getItemCount(): Int = data.size * 2
|
||||||
|
|
||||||
|
// stores and recycles views as they are scrolled off screen
|
||||||
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind(position: Int) {
|
||||||
|
if (data.isEmpty()) return
|
||||||
|
val dataPosition = floor(position / 2F).toInt()
|
||||||
|
binding.infoText.text = if (position % 2 == 0) data[dataPosition].first else data[dataPosition].second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
app/src/main/java/exh/ui/metadata/MetadataViewController.kt
Normal file
87
app/src/main/java/exh/ui/metadata/MetadataViewController.kt
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package exh.ui.metadata
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.databinding.MetadataViewControllerBinding
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.online.LewdSource.Companion.getLewdSource
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class MetadataViewController : NucleusController<MetadataViewControllerBinding, MetadataViewPresenter> {
|
||||||
|
constructor(manga: Manga?) : super(
|
||||||
|
Bundle().apply {
|
||||||
|
putLong(MangaController.MANGA_EXTRA, manga?.id ?: 0)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
this.manga = manga
|
||||||
|
if (manga != null) {
|
||||||
|
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(mangaId: Long) : this(
|
||||||
|
Injekt.get<DatabaseHelper>().getManga(mangaId).executeAsBlocking()
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
constructor(bundle: Bundle) : this(bundle.getLong(MangaController.MANGA_EXTRA))
|
||||||
|
|
||||||
|
var data = emptyList<Pair<String, String>>()
|
||||||
|
|
||||||
|
var adapter: MetadataViewAdapter? = null
|
||||||
|
|
||||||
|
var manga: Manga? = null
|
||||||
|
private set
|
||||||
|
var source: Source? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun getTitle(): String? {
|
||||||
|
return manga?.title
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
|
binding = MetadataViewControllerBinding.inflate(inflater)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPresenter(): MetadataViewPresenter {
|
||||||
|
return MetadataViewPresenter(
|
||||||
|
manga!!,
|
||||||
|
source!!
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View) {
|
||||||
|
super.onViewCreated(view)
|
||||||
|
|
||||||
|
if (manga == null || source == null) return
|
||||||
|
binding.recycler.layoutManager = GridLayoutManager(view.context, 2)
|
||||||
|
adapter = MetadataViewAdapter(data)
|
||||||
|
binding.recycler.adapter = adapter
|
||||||
|
binding.recycler.setHasFixedSize(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNextMetaInfo(flatMetadata: FlatMetadata) {
|
||||||
|
val thisSourceAsLewdSource = presenter.source.getLewdSource()
|
||||||
|
if (thisSourceAsLewdSource != null) {
|
||||||
|
presenter.meta = flatMetadata.raise(thisSourceAsLewdSource.metaClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onNextMangaInfo(meta: RaisedSearchMetadata?) {
|
||||||
|
val context = view?.context ?: return
|
||||||
|
data = meta?.getExtraInfoPairs(context) ?: emptyList()
|
||||||
|
adapter?.update(data)
|
||||||
|
}
|
||||||
|
}
|
48
app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt
Normal file
48
app/src/main/java/exh/ui/metadata/MetadataViewPresenter.kt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package exh.ui.metadata
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import timber.log.Timber
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class MetadataViewPresenter(
|
||||||
|
val manga: Manga,
|
||||||
|
val source: Source,
|
||||||
|
val preferences: PreferencesHelper = Injekt.get(),
|
||||||
|
private val db: DatabaseHelper = Injekt.get()
|
||||||
|
) : BasePresenter<MetadataViewController>() {
|
||||||
|
|
||||||
|
var meta: RaisedSearchMetadata? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedState: Bundle?) {
|
||||||
|
super.onCreate(savedState)
|
||||||
|
|
||||||
|
getMangaMetaObservable().subscribeLatestCache({ view, flatMetadata -> if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else Timber.d("Invalid metadata") })
|
||||||
|
|
||||||
|
getMangaObservable()
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeLatestCache({ view, _ -> view.onNextMangaInfo(meta) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMangaObservable(): Observable<Manga> {
|
||||||
|
return db.getManga(manga.url, manga.source).asRxObservable()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getMangaMetaObservable(): Observable<FlatMetadata?> {
|
||||||
|
val mangaId = manga.id
|
||||||
|
return if (mangaId != null) {
|
||||||
|
db.getFlatMetadataForManga(mangaId).asRxObservable()
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
} else Observable.just(null)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterEhBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
|
import exh.metadata.humanReadableByteCount
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class EHentaiDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<EHentaiDescriptionAdapter.EHentaiDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterEhBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EHentaiDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterEhBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return EHentaiDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: EHentaiDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class EHentaiDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is EHentaiSearchMetadata) return
|
||||||
|
|
||||||
|
val genre = meta.genre
|
||||||
|
if (genre != null) {
|
||||||
|
val pair = when (genre) {
|
||||||
|
"doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"artistcg" -> Pair("#dde500", R.string.artist_cg)
|
||||||
|
"gamecg" -> Pair("#05bf0b", R.string.game_cg)
|
||||||
|
"western" -> Pair("#14e723", R.string.western)
|
||||||
|
"non-h" -> Pair("#08d7e2", R.string.non_h)
|
||||||
|
"imageset" -> Pair("#5f5fff", R.string.image_set)
|
||||||
|
"cosplay" -> Pair("#9755f5", R.string.cosplay)
|
||||||
|
"asianporn" -> Pair("#fe93ff", R.string.asian_porn)
|
||||||
|
"misc" -> Pair("#9e9e9e", R.string.misc)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = genre
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
binding.visible.text = itemView.context.getString(R.string.is_visible, meta.visible ?: itemView.context.getString(R.string.unknown))
|
||||||
|
|
||||||
|
binding.favorites.text = (meta.favorites ?: 0).toString()
|
||||||
|
val drawable = itemView.context.getDrawable(R.drawable.ic_favorite_24dp)
|
||||||
|
drawable?.setTint(itemView.context.getResourceColor(R.attr.colorAccent))
|
||||||
|
binding.favorites.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||||
|
|
||||||
|
binding.whenPosted.text = EX_DATE_FORMAT.format(Date(meta.datePosted ?: 0))
|
||||||
|
|
||||||
|
binding.uploader.text = meta.uploader ?: itemView.context.getString(R.string.unknown)
|
||||||
|
binding.size.text = humanReadableByteCount(meta.size ?: 0, true)
|
||||||
|
binding.pages.text = itemView.context.getString(R.string.num_pages, meta.length ?: 0)
|
||||||
|
val language = meta.language ?: itemView.context.getString(R.string.unknown)
|
||||||
|
binding.language.text = if (meta.translated == true) {
|
||||||
|
itemView.context.getString(R.string.language_translated, language)
|
||||||
|
} else {
|
||||||
|
language
|
||||||
|
}
|
||||||
|
|
||||||
|
val ratingFloat = meta.averageRating?.toFloat()
|
||||||
|
val name = when (((ratingFloat ?: 100F) * 2).roundToInt()) {
|
||||||
|
0 -> R.string.rating0
|
||||||
|
1 -> R.string.rating1
|
||||||
|
2 -> R.string.rating2
|
||||||
|
3 -> R.string.rating3
|
||||||
|
4 -> R.string.rating4
|
||||||
|
5 -> R.string.rating5
|
||||||
|
6 -> R.string.rating6
|
||||||
|
7 -> R.string.rating7
|
||||||
|
8 -> R.string.rating8
|
||||||
|
9 -> R.string.rating9
|
||||||
|
10 -> R.string.rating10
|
||||||
|
else -> R.string.no_rating
|
||||||
|
}
|
||||||
|
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||||
|
binding.rating.text = if (meta.ratingCount != null) {
|
||||||
|
itemView.context.getString(R.string.rating_view, itemView.context.getString(name), (ratingFloat ?: 0F).toString(), meta.ratingCount ?: 0)
|
||||||
|
} else {
|
||||||
|
itemView.context.getString(R.string.rating_view_no_count, itemView.context.getString(name), (ratingFloat ?: 0F).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapter8mBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class EightMusesDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<EightMusesDescriptionAdapter.EightMusesDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapter8mBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EightMusesDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapter8mBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return EightMusesDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: EightMusesDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class EightMusesDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is EightMusesSearchMetadata) return
|
||||||
|
|
||||||
|
binding.title.text = meta.title ?: itemView.context.getString(R.string.unknown)
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHbBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class HBrowseDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<HBrowseDescriptionAdapter.HBrowseDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterHbBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HBrowseDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterHbBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return HBrowseDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: HBrowseDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class HBrowseDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is HBrowseSearchMetadata) return
|
||||||
|
|
||||||
|
binding.pages.text = itemView.context.getString(R.string.num_pages, meta.length ?: 0)
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHcBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.HentaiCafeSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class HentaiCafeDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<HentaiCafeDescriptionAdapter.HentaiCafeDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterHcBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HentaiCafeDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterHcBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return HentaiCafeDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: HentaiCafeDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class HentaiCafeDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is HentaiCafeSearchMetadata) return
|
||||||
|
|
||||||
|
binding.artist.text = meta.artist ?: itemView.context.getString(R.string.unknown)
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHiBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
|
import exh.metadata.metadata.HitomiSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import java.util.Date
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class HitomiDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<HitomiDescriptionAdapter.HitomiDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterHiBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HitomiDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterHiBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return HitomiDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: HitomiDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class HitomiDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is HitomiSearchMetadata) return
|
||||||
|
|
||||||
|
val genre = meta.type
|
||||||
|
if (genre != null) {
|
||||||
|
val pair = when (genre) {
|
||||||
|
"doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"artist CG" -> Pair("#dde500", R.string.artist_cg)
|
||||||
|
"game CG" -> Pair("#05bf0b", R.string.game_cg)
|
||||||
|
"western" -> Pair("#14e723", R.string.western)
|
||||||
|
"non-H" -> Pair("#08d7e2", R.string.non_h)
|
||||||
|
"image Set" -> Pair("#5f5fff", R.string.image_set)
|
||||||
|
"cosplay" -> Pair("#9755f5", R.string.cosplay)
|
||||||
|
"asian Porn" -> Pair("#fe93ff", R.string.asian_porn)
|
||||||
|
"misc" -> Pair("#9e9e9e", R.string.misc)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = genre
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
binding.whenPosted.text = EX_DATE_FORMAT.format(Date(meta.uploadDate ?: 0))
|
||||||
|
binding.group.text = meta.group ?: itemView.context.getString(R.string.unknown)
|
||||||
|
binding.language.text = meta.language ?: itemView.context.getString(R.string.unknown)
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterNhBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import java.util.Date
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class NHentaiDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<NHentaiDescriptionAdapter.NHentaiDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterNhBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NHentaiDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterNhBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return NHentaiDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: NHentaiDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class NHentaiDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is NHentaiSearchMetadata) return
|
||||||
|
|
||||||
|
var category: String? = null
|
||||||
|
meta.tags.filter { it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE }.let {
|
||||||
|
if (it.isNotEmpty()) category = it.joinToString(transform = { it.name })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (category != null) {
|
||||||
|
val pair = when (category) {
|
||||||
|
"doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"artistcg" -> Pair("#dde500", R.string.artist_cg)
|
||||||
|
"gamecg" -> Pair("#05bf0b", R.string.game_cg)
|
||||||
|
"western" -> Pair("#14e723", R.string.western)
|
||||||
|
"non-h" -> Pair("#08d7e2", R.string.non_h)
|
||||||
|
"imageset" -> Pair("#5f5fff", R.string.image_set)
|
||||||
|
"cosplay" -> Pair("#9755f5", R.string.cosplay)
|
||||||
|
"asianporn" -> Pair("#fe93ff", R.string.asian_porn)
|
||||||
|
"misc" -> Pair("#9e9e9e", R.string.misc)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = category
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
meta.favoritesCount?.let {
|
||||||
|
if (it == 0L) return@let
|
||||||
|
binding.favorites.text = it.toString()
|
||||||
|
|
||||||
|
val drawable = itemView.context.getDrawable(R.drawable.ic_favorite_24dp)
|
||||||
|
drawable?.setTint(itemView.context.getResourceColor(R.attr.colorAccent))
|
||||||
|
|
||||||
|
binding.favorites.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.whenPosted.text = EX_DATE_FORMAT.format(Date((meta.uploadDate ?: 0) * 1000))
|
||||||
|
|
||||||
|
binding.pages.text = itemView.context.getString(R.string.num_pages, meta.pageImageTypes.size)
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
binding.id.text = "#" + (meta.nhId ?: 0)
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPeBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import java.util.Locale
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class PervEdenDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<PervEdenDescriptionAdapter.PervEdenDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterPeBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PervEdenDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterPeBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return PervEdenDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PervEdenDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class PervEdenDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is PervEdenSearchMetadata) return
|
||||||
|
|
||||||
|
val genre = meta.type
|
||||||
|
if (genre != null) {
|
||||||
|
val pair = when (genre) {
|
||||||
|
"Doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"Japanese Manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"Korean Manhwa" -> Pair("#dde500", R.string.manhwa)
|
||||||
|
"Chinese Manhua" -> Pair("#05bf0b", R.string.manhua)
|
||||||
|
"Comic" -> Pair("#14e723", R.string.comic)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = genre
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
val language = meta.lang
|
||||||
|
binding.language.text = if (language != null) {
|
||||||
|
val local = Locale(language)
|
||||||
|
local.displayName
|
||||||
|
} else itemView.context.getString(R.string.unknown)
|
||||||
|
|
||||||
|
val name = when (((meta.rating ?: 100F) * 2).roundToInt()) {
|
||||||
|
0 -> R.string.rating0
|
||||||
|
1 -> R.string.rating1
|
||||||
|
2 -> R.string.rating2
|
||||||
|
3 -> R.string.rating3
|
||||||
|
4 -> R.string.rating4
|
||||||
|
5 -> R.string.rating5
|
||||||
|
6 -> R.string.rating6
|
||||||
|
7 -> R.string.rating7
|
||||||
|
8 -> R.string.rating8
|
||||||
|
9 -> R.string.rating9
|
||||||
|
10 -> R.string.rating10
|
||||||
|
else -> R.string.no_rating
|
||||||
|
}
|
||||||
|
binding.ratingBar.rating = meta.rating ?: 0F
|
||||||
|
binding.rating.text = itemView.context.getString(R.string.rating_view_no_count, itemView.context.getString(name), (meta.rating ?: 0F).toString())
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPuBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import exh.metadata.metadata.PururinSearchMetadata
|
||||||
|
import exh.metadata.metadata.PururinSearchMetadata.Companion.TAG_NAMESPACE_CATEGORY
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class PururinDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<PururinDescriptionAdapter.PururinDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterPuBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PururinDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterPuBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return PururinDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PururinDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class PururinDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is PururinSearchMetadata) return
|
||||||
|
|
||||||
|
val genre = meta.tags.find { it.namespace == TAG_NAMESPACE_CATEGORY }
|
||||||
|
if (genre != null) {
|
||||||
|
val pair = when (genre.name) {
|
||||||
|
"doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"artist-cg" -> Pair("#dde500", R.string.artist_cg)
|
||||||
|
"game-cg" -> Pair("#05bf0b", R.string.game_cg)
|
||||||
|
"artbook" -> Pair("#5f5fff", R.string.artbook)
|
||||||
|
"webtoon" -> Pair("#5f5fff", R.string.webtoon)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = genre.name
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
binding.uploader.text = meta.uploaderDisp ?: meta.uploader ?: ""
|
||||||
|
binding.size.text = meta.fileSize ?: itemView.context.getString(R.string.unknown)
|
||||||
|
binding.pages.text = itemView.context.getString(R.string.num_pages, meta.pages ?: 0)
|
||||||
|
|
||||||
|
val ratingFloat = meta.averageRating?.toFloat()
|
||||||
|
val name = when (((ratingFloat ?: 100F) * 2).roundToInt()) {
|
||||||
|
0 -> R.string.rating0
|
||||||
|
1 -> R.string.rating1
|
||||||
|
2 -> R.string.rating2
|
||||||
|
3 -> R.string.rating3
|
||||||
|
4 -> R.string.rating4
|
||||||
|
5 -> R.string.rating5
|
||||||
|
6 -> R.string.rating6
|
||||||
|
7 -> R.string.rating7
|
||||||
|
8 -> R.string.rating8
|
||||||
|
9 -> R.string.rating9
|
||||||
|
10 -> R.string.rating10
|
||||||
|
else -> R.string.no_rating
|
||||||
|
}
|
||||||
|
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||||
|
binding.rating.text = if (meta.ratingCount != null) {
|
||||||
|
itemView.context.getString(R.string.rating_view, itemView.context.getString(name), (ratingFloat ?: 0F).toString(), meta.ratingCount ?: 0)
|
||||||
|
} else {
|
||||||
|
itemView.context.getString(R.string.rating_view_no_count, itemView.context.getString(name), (ratingFloat ?: 0F).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,107 @@
|
|||||||
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterTsBinding
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
|
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||||
|
import exh.ui.metadata.MetadataViewController
|
||||||
|
import java.util.Date
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
|
||||||
|
class TsuminoDescriptionAdapter(
|
||||||
|
private val controller: MangaController
|
||||||
|
) :
|
||||||
|
RecyclerView.Adapter<TsuminoDescriptionAdapter.TsuminoDescriptionViewHolder>() {
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
private lateinit var binding: DescriptionAdapterTsBinding
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TsuminoDescriptionViewHolder {
|
||||||
|
binding = DescriptionAdapterTsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
return TsuminoDescriptionViewHolder(binding.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = 1
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: TsuminoDescriptionViewHolder, position: Int) {
|
||||||
|
holder.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class TsuminoDescriptionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
fun bind() {
|
||||||
|
val meta = controller.presenter.meta
|
||||||
|
if (meta == null || meta !is TsuminoSearchMetadata) return
|
||||||
|
|
||||||
|
val genre = meta.category
|
||||||
|
if (genre != null) {
|
||||||
|
val pair = when (genre) {
|
||||||
|
"Doujinshi" -> Pair("#fc4e4e", R.string.doujinshi)
|
||||||
|
"Manga" -> Pair("#e78c1a", R.string.manga)
|
||||||
|
"Artist CG" -> Pair("#dde500", R.string.artist_cg)
|
||||||
|
"Game CG" -> Pair("#05bf0b", R.string.game_cg)
|
||||||
|
"Video" -> Pair("#14e723", R.string.video)
|
||||||
|
else -> Pair("", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pair.first.isNotBlank()) {
|
||||||
|
binding.genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||||
|
binding.genre.text = itemView.context.getString(pair.second)
|
||||||
|
} else binding.genre.text = genre
|
||||||
|
} else binding.genre.setText(R.string.unknown)
|
||||||
|
|
||||||
|
binding.favorites.text = (meta.favorites ?: 0).toString()
|
||||||
|
val drawable = itemView.context.getDrawable(R.drawable.ic_favorite_24dp)
|
||||||
|
drawable?.setTint(itemView.context.getResourceColor(R.attr.colorAccent))
|
||||||
|
binding.favorites.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
|
||||||
|
|
||||||
|
binding.whenPosted.text = TsuminoSearchMetadata.TSUMINO_DATE_FORMAT.format(Date(meta.uploadDate ?: 0))
|
||||||
|
|
||||||
|
binding.uploader.text = meta.uploader ?: itemView.context.getString(R.string.unknown)
|
||||||
|
binding.pages.text = itemView.context.getString(R.string.num_pages, meta.length ?: 0)
|
||||||
|
|
||||||
|
val name = when (((meta.averageRating ?: 100F) * 2).roundToInt()) {
|
||||||
|
0 -> R.string.rating0
|
||||||
|
1 -> R.string.rating1
|
||||||
|
2 -> R.string.rating2
|
||||||
|
3 -> R.string.rating3
|
||||||
|
4 -> R.string.rating4
|
||||||
|
5 -> R.string.rating5
|
||||||
|
6 -> R.string.rating6
|
||||||
|
7 -> R.string.rating7
|
||||||
|
8 -> R.string.rating8
|
||||||
|
9 -> R.string.rating9
|
||||||
|
10 -> R.string.rating10
|
||||||
|
else -> R.string.no_rating
|
||||||
|
}
|
||||||
|
binding.ratingBar.rating = meta.averageRating ?: 0F
|
||||||
|
binding.rating.text = if (meta.userRatings != null) {
|
||||||
|
itemView.context.getString(R.string.rating_view, itemView.context.getString(name), (meta.averageRating ?: 0F).toString(), meta.userRatings ?: 0L)
|
||||||
|
} else {
|
||||||
|
itemView.context.getString(R.string.rating_view_no_count, itemView.context.getString(name), (meta.averageRating ?: 0F).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.moreInfo.clicks()
|
||||||
|
.onEach {
|
||||||
|
controller.router?.pushController(
|
||||||
|
MetadataViewController(
|
||||||
|
controller.manga
|
||||||
|
).withFadeTransaction()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,11 @@ import android.widget.FrameLayout
|
|||||||
import androidx.annotation.Px
|
import androidx.annotation.Px
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import com.google.android.material.chip.ChipGroup
|
import com.google.android.material.chip.ChipGroup
|
||||||
|
import exh.EH_SOURCE_ID
|
||||||
|
import exh.EXH_SOURCE_ID
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_LIGHT
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_NORMAL
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata.Companion.TAG_TYPE_WEAK
|
||||||
|
|
||||||
inline val View.marginTop: Int
|
inline val View.marginTop: Int
|
||||||
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin ?: 0
|
get() = (layoutParams as? ViewGroup.MarginLayoutParams)?.topMargin ?: 0
|
||||||
@ -120,7 +125,7 @@ fun ChipGroup.setChipsExtended(items: List<String>?, onClick: (item: String) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}, sourceId: Long, context: Context, namespace: String? = null): Chip {
|
fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}, sourceId: Long, context: Context, namespace: String? = null, type: Int? = null): Chip {
|
||||||
return Chip(context).apply {
|
return Chip(context).apply {
|
||||||
text = item
|
text = item
|
||||||
val search = (if (namespace != null) SourceTagsUtil().getWrappedTag(sourceId, namespace = namespace, tag = item) else SourceTagsUtil().getWrappedTag(sourceId, fullTag = item)) ?: item
|
val search = (if (namespace != null) SourceTagsUtil().getWrappedTag(sourceId, namespace = namespace, tag = item) else SourceTagsUtil().getWrappedTag(sourceId, fullTag = item)) ?: item
|
||||||
@ -129,5 +134,13 @@ fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongCli
|
|||||||
onLongClick(search)
|
onLongClick(search)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID) {
|
||||||
|
chipStrokeWidth = when (type) {
|
||||||
|
TAG_TYPE_NORMAL -> 5F
|
||||||
|
TAG_TYPE_LIGHT -> 3F
|
||||||
|
TAG_TYPE_WEAK -> 0F
|
||||||
|
else -> chipStrokeWidth
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
app/src/main/res/drawable/border.xml
Normal file
7
app/src/main/res/drawable/border.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<stroke
|
||||||
|
android:width="1dip"
|
||||||
|
android:color="?attr/colorOnSurface" />
|
||||||
|
</shape>
|
35
app/src/main/res/layout/description_adapter_8m.xml
Normal file
35
app/src/main/res/layout/description_adapter_8m.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
146
app/src/main/res/layout/description_adapter_eh.xml
Normal file
146
app/src/main/res/layout/description_adapter_eh.xml
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/pages"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/language"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/size"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/favorites"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/language" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/when_posted"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/size" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/visible"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/favorites" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/uploader"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/when_posted" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatRatingBar
|
||||||
|
android:id="@+id/rating_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:numStars="5"
|
||||||
|
android:stepSize="0.1"
|
||||||
|
android:isIndicator="true"
|
||||||
|
android:focusable="false"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/rating"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/rating_bar" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
34
app/src/main/res/layout/description_adapter_hb.xml
Normal file
34
app/src/main/res/layout/description_adapter_hb.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/pages"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
34
app/src/main/res/layout/description_adapter_hc.xml
Normal file
34
app/src/main/res/layout/description_adapter_hc.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/artist"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
80
app/src/main/res/layout/description_adapter_hi.xml
Normal file
80
app/src/main/res/layout/description_adapter_hi.xml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/language"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/when_posted"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/group"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
90
app/src/main/res/layout/description_adapter_nh.xml
Normal file
90
app/src/main/res/layout/description_adapter_nh.xml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/pages"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/id"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/favorites"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/when_posted"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
82
app/src/main/res/layout/description_adapter_pe.xml
Normal file
82
app/src/main/res/layout/description_adapter_pe.xml
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/language"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatRatingBar
|
||||||
|
android:id="@+id/rating_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:numStars="5"
|
||||||
|
android:stepSize="0.1"
|
||||||
|
android:isIndicator="true"
|
||||||
|
android:focusable="false"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/rating"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/rating_bar" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
107
app/src/main/res/layout/description_adapter_pu.xml
Normal file
107
app/src/main/res/layout/description_adapter_pu.xml
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/pages"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/uploader"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/size"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatRatingBar
|
||||||
|
android:id="@+id/rating_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:numStars="5"
|
||||||
|
android:stepSize="0.1"
|
||||||
|
android:isIndicator="true"
|
||||||
|
android:focusable="false"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/rating"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/rating_bar" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
117
app/src/main/res/layout/description_adapter_ts.xml
Normal file
117
app/src/main/res/layout/description_adapter_ts.xml
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/cardView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/genre"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingBottom="4dp" />
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/pages"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/more_info"
|
||||||
|
style="@style/Theme.Widget.Button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/more_info"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/favorites"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/when_posted"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/uploader"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatRatingBar
|
||||||
|
android:id="@+id/rating_bar"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:numStars="5"
|
||||||
|
android:stepSize="0.1"
|
||||||
|
android:isIndicator="true"
|
||||||
|
android:focusable="false"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/rating"
|
||||||
|
style="@style/TextAppearance.Regular"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/rating_bar" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
35
app/src/main/res/layout/manga_info_buttons.xml
Normal file
35
app/src/main/res/layout/manga_info_buttons.xml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/merge_btn"
|
||||||
|
style="@style/Theme.Widget.Button.FilledAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/merge_with_another_source"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/recommend_btn"
|
||||||
|
style="@style/Theme.Widget.Button.FilledAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/az_recommends"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</LinearLayout>
|
@ -194,132 +194,4 @@
|
|||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_summary_label"
|
|
||||||
style="@style/TextAppearance.Regular.SubHeading"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:text="@string/manga_info_about_label"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/manga_info_toggle"
|
|
||||||
style="@style/Theme.Widget.Button.Icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:text="@string/manga_info_expand"
|
|
||||||
app:icon="@drawable/ic_baseline_expand_more_24dp"
|
|
||||||
app:iconTint="?attr/colorOnPrimary"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/manga_summary"
|
|
||||||
style="@style/TextAppearance.Regular.Body1.Secondary"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:clickable="true"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:focusable="true"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:textIsSelectable="false"
|
|
||||||
tools:text="Summary" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/manga_namespace_tags_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:listitem="@layout/manga_info_genre_grouping"/>
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/manga_genres_tags_wrapper"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/manga_genres_tags_full_chips"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:chipSpacingHorizontal="4dp" />
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
|
||||||
android:id="@+id/manga_genres_tags_compact"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:requiresFadingEdge="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/manga_genres_tags_compact_chips"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="16dp"
|
|
||||||
app:chipSpacingHorizontal="4dp"
|
|
||||||
app:singleLine="true" />
|
|
||||||
|
|
||||||
</HorizontalScrollView>
|
|
||||||
|
|
||||||
</FrameLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/merge_btn"
|
|
||||||
style="@style/Theme.Widget.Button.FilledAccent"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:text="@string/merge_with_another_source"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/recommend_btn"
|
|
||||||
style="@style/Theme.Widget.Button.FilledAccent"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="4dp"
|
|
||||||
android:text="@string/az_recommends"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
110
app/src/main/res/layout/manga_info_item.xml
Normal file
110
app/src/main/res/layout/manga_info_item.xml
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/manga_summary_label"
|
||||||
|
style="@style/TextAppearance.Regular.SubHeading"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:text="@string/manga_info_about_label"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/manga_info_toggle"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/manga_info_toggle"
|
||||||
|
style="@style/Theme.Widget.Button.Icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:text="@string/manga_info_expand"
|
||||||
|
app:icon="@drawable/ic_baseline_expand_more_24dp"
|
||||||
|
app:iconTint="?attr/colorOnPrimary"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/manga_summary"
|
||||||
|
style="@style/TextAppearance.Regular.Body1.Secondary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:focusable="true"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textIsSelectable="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="Summary"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/manga_genres_tags_wrapper"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/manga_genres_tags_full_chips"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:chipSpacingHorizontal="4dp" />
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/manga_genres_tags_compact"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:requiresFadingEdge="horizontal">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/manga_genres_tags_compact_chips"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
app:chipSpacingHorizontal="4dp"
|
||||||
|
app:singleLine="true" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/genre_groups"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
tools:listitem="@layout/manga_info_genre_grouping" />
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
14
app/src/main/res/layout/metadata_view_controller.xml
Normal file
14
app/src/main/res/layout/metadata_view_controller.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:listitem="@layout/metadata_view_item"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
15
app/src/main/res/layout/metadata_view_item.xml
Normal file
15
app/src/main/res/layout/metadata_view_item.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/border">
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/info_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
style="@style/TextAppearance.Regular" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -345,4 +345,80 @@
|
|||||||
<string name="manga_id_is_null">Manga ID is null!</string>
|
<string name="manga_id_is_null">Manga ID is null!</string>
|
||||||
<string name="loading_gallery">Loading gallery…</string>
|
<string name="loading_gallery">Loading gallery…</string>
|
||||||
|
|
||||||
|
<!-- Rating 0-10 (0, 0.5, 1, 1.5 and so fourth) -->
|
||||||
|
<string name="rating10">Masterpiece</string>
|
||||||
|
<string name="rating9">Amazing</string>
|
||||||
|
<string name="rating8">Great</string>
|
||||||
|
<string name="rating7">Good</string>
|
||||||
|
<string name="rating6">Okay</string>
|
||||||
|
<string name="rating5">Mediocre</string>
|
||||||
|
<string name="rating4">Bad</string>
|
||||||
|
<string name="rating3">Awful</string>
|
||||||
|
<string name="rating2">Painful</string>
|
||||||
|
<string name="rating1">Unbearable</string>
|
||||||
|
<string name="rating0">Disaster</string>
|
||||||
|
<string name="no_rating">No rating</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Gallery types -->
|
||||||
|
<string name="doujinshi">Doujinshi</string>
|
||||||
|
<string name="artist_cg">Artist CG</string>
|
||||||
|
<string name="game_cg">Game CG</string>
|
||||||
|
<string name="western">Western</string>
|
||||||
|
<string name="non_h">Non-H</string>
|
||||||
|
<string name="image_set">Image Set</string>
|
||||||
|
<string name="cosplay">Cosplay</string>
|
||||||
|
<string name="asian_porn">Asian Porn</string>
|
||||||
|
<string name="misc">Misc</string>
|
||||||
|
<string name="artbook">Artbook</string>
|
||||||
|
<string name="video">Video</string>
|
||||||
|
|
||||||
|
<!-- More Info Menu -->
|
||||||
|
<string name="more_info">More Info</string>
|
||||||
|
<string name="alt_title">Alt Title</string>
|
||||||
|
<string name="id">Id</string>
|
||||||
|
<string name="token">Token</string>
|
||||||
|
<string name="is_exhentai_gallery">is Exhentai gallery</string>
|
||||||
|
<string name="thumbnail_url">Thumbnail url</string>
|
||||||
|
<string name="genre">Genre</string>
|
||||||
|
<string name="date_posted">Date posted</string>
|
||||||
|
<string name="page_count">Page count</string>
|
||||||
|
<string name="parent">Parent</string>
|
||||||
|
<string name="visible">Visible</string>
|
||||||
|
<string name="language">Language</string>
|
||||||
|
<string name="gallery_size">Gallery size</string>
|
||||||
|
<string name="total_favorites">Total favorites</string>
|
||||||
|
<string name="total_ratings">Total ratings</string>
|
||||||
|
<string name="average_rating">Average rating</string>
|
||||||
|
<string name="aged">Aged</string>
|
||||||
|
<string name="last_update_check">Last update check</string>
|
||||||
|
<string name="path">Path</string>
|
||||||
|
<string name="artist">Artist</string>
|
||||||
|
<string name="reader_id">Reader id</string>
|
||||||
|
<string name="series">Series</string>
|
||||||
|
<string name="characters">Characters</string>
|
||||||
|
<string name="group">Group</string>
|
||||||
|
<string name="media_id">Media id</string>
|
||||||
|
<string name="japanese_title">Japanese Title</string>
|
||||||
|
<string name="english_title">English Title</string>
|
||||||
|
<string name="short_title">Short Title</string>
|
||||||
|
<string name="cover_image_file_type">Cover image file type</string>
|
||||||
|
<string name="thumbnail_image_file_type">Thumbnail image file type</string>
|
||||||
|
<string name="scanlator">Scanlator</string>
|
||||||
|
<string name="url">Url</string>
|
||||||
|
<string name="alt_titles">Alt titles</string>
|
||||||
|
<string name="uploader_capital">Uploader Capitalized</string>
|
||||||
|
<string name="uploader">Uploader</string>
|
||||||
|
<string name="rating_string">Rating string</string>
|
||||||
|
<string name="collection">Collection</string>
|
||||||
|
<string name="parodies">Parodies</string>
|
||||||
|
|
||||||
|
<!-- Extra gallery info -->
|
||||||
|
<string name="num_pages">%1$d pages</string>
|
||||||
|
<string name="tags">Tags</string>
|
||||||
|
<string name="is_visible">Visible: %1$s</string>
|
||||||
|
<string name="rating_view">%1$s (%2$s, %3$d)</string>
|
||||||
|
<string name="rating_view_no_count">%1$s (%2$s)</string>
|
||||||
|
<string name="language_translated">%1$s TR</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user