Add special view for browsing E/Exhentai! All the important info is now in front of your face when browsing, it is on by default and can be toggled off in the E-Hentai settings. Let me know if you find any errors
This commit is contained in:
parent
032504f128
commit
a6cba5c87d
@ -341,6 +341,9 @@ dependencies {
|
||||
// Humanize (EH)
|
||||
implementation 'com.github.mfornos:humanize-slim:1.2.2'
|
||||
|
||||
// RatingBar (SY)
|
||||
implementation 'me.zhanghai.android.materialratingbar:library:1.3.1'
|
||||
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
|
||||
final def markwon_version = '4.1.0'
|
||||
|
@ -272,4 +272,6 @@ object PreferenceKeys {
|
||||
const val recommendsInOverflow = "recommends_in_overflow"
|
||||
|
||||
const val hitomiAlwaysWebp = "hitomi_always_webp"
|
||||
|
||||
const val enhancedEHentaiView = "enhanced_e_hentai_view"
|
||||
}
|
||||
|
@ -380,4 +380,6 @@ class PreferencesHelper(val context: Context) {
|
||||
fun recommendsInOverflow() = flowPrefs.getBoolean(Keys.recommendsInOverflow, false)
|
||||
|
||||
fun hitomiAlwaysWebp() = flowPrefs.getBoolean(Keys.hitomiAlwaysWebp, true)
|
||||
|
||||
fun enhancedEHentaiView() = flowPrefs.getBoolean(Keys.enhancedEHentaiView, true)
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
package eu.kanade.tachiyomi.source.model
|
||||
|
||||
data class MangasPage(val mangas: List<SManga>, val hasNextPage: Boolean)
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
|
||||
/* SY --> */ open /* SY <-- */ class MangasPage(val mangas: List<SManga>, val hasNextPage: Boolean)
|
||||
|
||||
// SY -->
|
||||
class MetadataMangasPage(mangas: List<SManga>, hasNextPage: Boolean, val mangasMetadata: List<RaisedSearchMetadata>) : MangasPage(mangas, hasNextPage)
|
||||
// SY <--
|
||||
|
@ -18,7 +18,7 @@ import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
@ -96,9 +96,9 @@ class EHentai(
|
||||
/**
|
||||
* Gallery list entry
|
||||
*/
|
||||
data class ParsedManga(val fav: Int, val manga: Manga)
|
||||
data class ParsedManga(val fav: Int, val manga: Manga, val metadata: EHentaiSearchMetadata)
|
||||
|
||||
fun extendedGenericMangaParse(doc: Document) = with(doc) {
|
||||
private fun extendedGenericMangaParse(doc: Document) = with(doc) {
|
||||
// Parse mangas (supports compact + extended layout)
|
||||
val parsedMangas = select(".itg > tbody > tr").filter {
|
||||
// Do not parse header and ads
|
||||
@ -110,6 +110,8 @@ class EHentai(
|
||||
val infoElement = it.selectFirst(".gl3e")
|
||||
|
||||
val favElement = column2.children().find { it.attr("style").startsWith("border-color") }
|
||||
val infoElements = infoElement?.select("div")
|
||||
val parsedTags = mutableListOf<RaisedTag>()
|
||||
|
||||
ParsedManga(
|
||||
fav = FAVORITES_BORDER_HEX_COLORS.indexOf(
|
||||
@ -122,14 +124,10 @@ class EHentai(
|
||||
// Get image
|
||||
thumbnail_url = thumbnailElement.attr("src")
|
||||
|
||||
val tags = mutableListOf<RaisedTag>()
|
||||
|
||||
val infoElements = infoElement?.select("div")
|
||||
|
||||
if (infoElements != null) {
|
||||
linkElement.select("div div")?.getOrNull(1)?.select("tr")?.forEach { row ->
|
||||
val namespace = row.select(".tc").text().removeSuffix(":")
|
||||
tags.addAll(
|
||||
parsedTags.addAll(
|
||||
row.select("div").map { element ->
|
||||
RaisedTag(
|
||||
namespace,
|
||||
@ -143,46 +141,61 @@ class EHentai(
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
getGenre(infoElements[1])?.let { tags += it }
|
||||
|
||||
getDateTag(infoElements[2])?.let { tags += it }
|
||||
|
||||
getRating(infoElements[3])?.let { tags += it }
|
||||
|
||||
getAuthor(infoElements[4])?.let { author = it }
|
||||
} else {
|
||||
val tagElement = it.selectFirst(".gl3c > a")
|
||||
val tagElements = tagElement.select("div")
|
||||
tagElements.forEach { element ->
|
||||
if (element.className() == "gt") {
|
||||
val namespace = element.attr("title").substringBefore(":").trimOrNull() ?: "misc"
|
||||
tags += RaisedTag(
|
||||
parsedTags += RaisedTag(
|
||||
namespace,
|
||||
element.attr("title").substringAfter(":").trim(),
|
||||
TAG_TYPE_NORMAL
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val genre = it.selectFirst(".gl1c div")
|
||||
getGenre(genreString = genre?.text()?.nullIfBlank()?.toLowerCase()?.replace(" ", ""))?.let { tags += it }
|
||||
genre = parsedTags.toGenreString()
|
||||
},
|
||||
metadata = EHentaiSearchMetadata().apply {
|
||||
tags += parsedTags
|
||||
|
||||
if (infoElements != null) {
|
||||
getGenre(infoElements.getOrNull(1))?.let { genre = it }
|
||||
|
||||
getDateTag(infoElements.getOrNull(2))?.let { datePosted = it }
|
||||
|
||||
getRating(infoElements.getOrNull(3))?.let { averageRating = it }
|
||||
|
||||
getUploader(infoElements.getOrNull(4))?.let { uploader = it }
|
||||
|
||||
getPageCount(infoElements.getOrNull(5))?.let { length = it }
|
||||
} else {
|
||||
val parsedGenre = it.selectFirst(".gl1c div")
|
||||
getGenre(genreString = parsedGenre?.text()?.nullIfBlank()?.toLowerCase()?.replace(" ", ""))?.let { genre = it }
|
||||
|
||||
val info = it.selectFirst(".gl2c")
|
||||
val extraInfo = it.selectFirst(".gl4c")
|
||||
|
||||
val infoList = info.select("div div")
|
||||
|
||||
getDateTag(infoList[8])?.let { tags += it }
|
||||
getDateTag(infoList.getOrNull(8))?.let { datePosted = it }
|
||||
|
||||
getRating(infoList[9])?.let { tags += it }
|
||||
getRating(infoList.getOrNull(9))?.let { averageRating = it }
|
||||
|
||||
val extraInfoList = extraInfo.select("div")
|
||||
|
||||
getAuthor(extraInfoList[1])?.let { author = it }
|
||||
}
|
||||
if (extraInfoList.getOrNull(2) == null) {
|
||||
getUploader(extraInfoList.getOrNull(0))?.let { uploader = it }
|
||||
|
||||
genre = tags.toGenreString()
|
||||
getPageCount(extraInfoList.getOrNull(1))?.let { length = it }
|
||||
} else {
|
||||
getUploader(extraInfoList.getOrNull(1))?.let { uploader = it }
|
||||
|
||||
getPageCount(extraInfoList.getOrNull(2))?.let { length = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -202,68 +215,54 @@ class EHentai(
|
||||
Pair(parsedMangas, hasNextPage)
|
||||
}
|
||||
|
||||
private fun getGenre(element: Element? = null, genreString: String? = null): RaisedTag? {
|
||||
val attr = element?.attr("onclick")
|
||||
private fun getGenre(element: Element? = null, genreString: String? = null): String? {
|
||||
return element?.attr("onclick")
|
||||
?.nullIfBlank()
|
||||
?.substringAfterLast('/')
|
||||
?.removeSuffix("'")
|
||||
?.trim()
|
||||
?.substringAfterLast('/')
|
||||
?.removeSuffix("'") ?: genreString
|
||||
return if (attr != null) {
|
||||
RaisedTag(
|
||||
EH_GENRE_NAMESPACE,
|
||||
attr,
|
||||
TAG_TYPE_NORMAL
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun getDateTag(element: Element?): RaisedTag? {
|
||||
private fun getDateTag(element: Element?): Long? {
|
||||
val text = element?.text()?.nullIfBlank()
|
||||
return if (text != null) {
|
||||
val date = EX_DATE_FORMAT.parse(text)
|
||||
if (date != null) {
|
||||
RaisedTag(
|
||||
EH_DATE_POSTED_NAMESPACE,
|
||||
date.time.toString(),
|
||||
TAG_TYPE_NORMAL
|
||||
)
|
||||
} else null
|
||||
date?.time
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun getRating(element: Element?): RaisedTag? {
|
||||
private fun getRating(element: Element?): Double? {
|
||||
val ratingStyle = element?.attr("style")?.nullIfBlank()
|
||||
return if (ratingStyle != null) {
|
||||
val matches = "([0-9]*)px".toRegex().findAll(ratingStyle).mapNotNull { it.groupValues.getOrNull(1)?.toIntOrNull() }.toList()
|
||||
val matches = RATING_REGEX.findAll(ratingStyle).mapNotNull { it.groupValues.getOrNull(1)?.toIntOrNull() }.toList()
|
||||
if (matches.size == 2) {
|
||||
var rate = 5 - matches[0] / 16
|
||||
RaisedTag(
|
||||
EH_RATING_NAMESPACE,
|
||||
if (matches[1] == 21) {
|
||||
rate--
|
||||
"$rate.5"
|
||||
} else rate.toString(),
|
||||
TAG_TYPE_NORMAL
|
||||
)
|
||||
if (matches[1] == 21) {
|
||||
rate--
|
||||
rate + 0.5
|
||||
} else rate.toDouble()
|
||||
} else null
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun getAuthor(element: Element?): String? {
|
||||
return element?.select("a")
|
||||
?.attr("href")
|
||||
?.nullIfBlank()
|
||||
?.trim()
|
||||
?.substringAfterLast('/')
|
||||
private fun getUploader(element: Element?): String? {
|
||||
return element?.select("a")?.text()?.trimOrNull()
|
||||
}
|
||||
|
||||
private fun getPageCount(element: Element?): Int? {
|
||||
val pageCount = element?.text()?.trimOrNull()
|
||||
return if (pageCount != null) {
|
||||
PAGE_COUNT_REGEX.find(pageCount)?.value?.toIntOrNull()
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a list of galleries
|
||||
*/
|
||||
fun genericMangaParse(response: Response) = extendedGenericMangaParse(response.asJsoup()).let {
|
||||
MangasPage(it.first.map { it.manga }, it.second)
|
||||
MetadataMangasPage(it.first.map { it.manga }, it.second, it.first.map { it.metadata })
|
||||
}
|
||||
|
||||
override fun fetchChapterList(manga: SManga) = fetchChapterList(manga) {}
|
||||
@ -675,7 +674,7 @@ class EHentai(
|
||||
page++
|
||||
} while (parsed.second)
|
||||
|
||||
return Pair(result as List<ParsedManga>, favNames!!)
|
||||
return Pair(result.toList(), favNames!!)
|
||||
}
|
||||
|
||||
fun spPref() = if (exh) {
|
||||
@ -965,8 +964,8 @@ class EHentai(
|
||||
private const val QUERY_PREFIX = "?f_apply=Apply+Filter"
|
||||
private const val TR_SUFFIX = "TR"
|
||||
private const val REVERSE_PARAM = "TEH_REVERSE"
|
||||
private const val EH_DATE_POSTED_NAMESPACE = "date_posted"
|
||||
private const val EH_RATING_NAMESPACE = "rating"
|
||||
private val PAGE_COUNT_REGEX = "[0-9]*".toRegex()
|
||||
private val RATING_REGEX = "([0-9]*)px".toRegex()
|
||||
|
||||
private const val EH_API_BASE = "https://api.e-hentai.org/api.php"
|
||||
private val JSON = "application/json; charset=utf-8".toMediaTypeOrNull()!!
|
||||
|
@ -54,6 +54,7 @@ import eu.kanade.tachiyomi.util.view.snack
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import eu.kanade.tachiyomi.widget.EmptyView
|
||||
import exh.EXHSavedSearch
|
||||
import exh.isEhBasedSource
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.drop
|
||||
@ -348,7 +349,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
binding.catalogueView.removeView(oldRecycler)
|
||||
}
|
||||
|
||||
val recycler = if (preferences.sourceDisplayMode().get() == DisplayMode.LIST) {
|
||||
val recycler = if (preferences.sourceDisplayMode().get() == DisplayMode.LIST /* SY --> */ || (preferences.enhancedEHentaiView().get() && presenter.source.isEhBasedSource()) /* SY <-- */) {
|
||||
RecyclerView(view.context).apply {
|
||||
id = R.id.recycler
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
@ -439,6 +440,11 @@ open class BrowseSourceController(bundle: Bundle) :
|
||||
DisplayMode.LIST -> R.id.action_list
|
||||
}
|
||||
menu.findItem(displayItem).isChecked = true
|
||||
// SY -->
|
||||
if (preferences.enhancedEHentaiView().get() && presenter.source.isEhBasedSource()) {
|
||||
menu.findItem(R.id.action_display_mode).isVisible = false
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
|
@ -38,9 +38,9 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import exh.EXHSavedSearch
|
||||
import exh.isEhBasedSource
|
||||
import java.lang.RuntimeException
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.flow.subscribe
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@ -165,9 +165,13 @@ open class BrowseSourcePresenter(
|
||||
pagerSubscription?.let { remove(it) }
|
||||
pagerSubscription = pager.results()
|
||||
.observeOn(Schedulers.io())
|
||||
.map { pair -> pair.first to pair.second.map { networkToLocalManga(it, sourceId) } }
|
||||
// SY -->
|
||||
.map { triple -> Triple(triple.first, triple.second.map { networkToLocalManga(it, sourceId) }, triple.third) }
|
||||
// SY <--
|
||||
.doOnNext { initializeMangas(it.second) }
|
||||
.map { pair -> pair.first to pair.second.map { SourceItem(it, sourceDisplayMode) } }
|
||||
// SY -->
|
||||
.map { triple -> triple.first to triple.second.mapIndexed { index, manga -> SourceItem(manga, sourceDisplayMode, if (prefs.enhancedEHentaiView().get() && source.isEhBasedSource()) triple.third?.getOrNull(index) else null) } }
|
||||
// SY <--
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeReplay(
|
||||
{ view, (page, mangas) ->
|
||||
|
@ -2,7 +2,9 @@ package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import rx.Observable
|
||||
|
||||
/**
|
||||
@ -13,9 +15,9 @@ abstract class Pager(var currentPage: Int = 1) {
|
||||
var hasNextPage = true
|
||||
private set
|
||||
|
||||
protected val results: PublishRelay<Pair<Int, List<SManga>>> = PublishRelay.create()
|
||||
protected val results: PublishRelay< /* SY --> */ Triple /* SY <-- */ <Int, List<SManga> /* SY --> */, List<RaisedSearchMetadata>? /* SY <-- */ >> = PublishRelay.create()
|
||||
|
||||
fun results(): Observable<Pair<Int, List<SManga>>> {
|
||||
fun results(): Observable< /* SY --> */ Triple /* SY <-- */ <Int, List<SManga> /* SY --> */, List<RaisedSearchMetadata>?> /* SY <-- */> {
|
||||
return results.asObservable()
|
||||
}
|
||||
|
||||
@ -25,6 +27,11 @@ abstract class Pager(var currentPage: Int = 1) {
|
||||
val page = currentPage
|
||||
currentPage++
|
||||
hasNextPage = mangasPage.hasNextPage && mangasPage.mangas.isNotEmpty()
|
||||
results.call(Pair(page, mangasPage.mangas))
|
||||
// SY -->
|
||||
val mangasMetadata = if (mangasPage is MetadataMangasPage) {
|
||||
mangasPage.mangasMetadata
|
||||
} else null
|
||||
// SY <--
|
||||
results.call( /* SY <-- */ Triple /* SY <-- */ (page, mangasPage.mangas /* SY --> */, mangasMetadata /* SY <-- */))
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||
|
||||
import android.graphics.Color
|
||||
import android.view.View
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import exh.util.SourceTagsUtil
|
||||
import exh.util.SourceTagsUtil.Companion.getLocaleSourceUtil
|
||||
import java.util.Date
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.date_posted
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.genre
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.language
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.rating_bar
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.thumbnail
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.title
|
||||
import kotlinx.android.synthetic.main.source_enhanced_ehentai_list_item.uploader
|
||||
|
||||
/**
|
||||
* Class used to hold the displayed data of a manga in the catalogue, like the cover or the title.
|
||||
* All the elements from the layout file "item_catalogue_list" are available in this class.
|
||||
*
|
||||
* @param view the inflated view for this holder.
|
||||
* @param adapter the adapter handling this holder.
|
||||
* @constructor creates a new catalogue holder.
|
||||
*/
|
||||
class SourceEnhancedEHentaiListHolder(private val view: View, adapter: FlexibleAdapter<*>) :
|
||||
SourceHolder(view, adapter) {
|
||||
|
||||
private val favoriteColor = view.context.getResourceColor(R.attr.colorOnSurface, 0.38f)
|
||||
private val unfavoriteColor = view.context.getResourceColor(R.attr.colorOnSurface)
|
||||
|
||||
/**
|
||||
* Method called from [CatalogueAdapter.onBindViewHolder]. It updates the data for this
|
||||
* holder with the given manga.
|
||||
*
|
||||
* @param manga the manga to bind.
|
||||
*/
|
||||
override fun onSetValues(manga: Manga) {
|
||||
title.text = manga.title
|
||||
title.setTextColor(if (manga.favorite) favoriteColor else unfavoriteColor)
|
||||
|
||||
// Set alpha of thumbnail.
|
||||
thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
|
||||
|
||||
setImage(manga)
|
||||
}
|
||||
|
||||
fun onSetMetadataValues(manga: Manga, metadata: RaisedSearchMetadata) {
|
||||
if (metadata !is EHentaiSearchMetadata) return
|
||||
|
||||
if (metadata.uploader != null) {
|
||||
uploader.text = metadata.uploader
|
||||
}
|
||||
|
||||
val pair = when (metadata.genre) {
|
||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"artistcg" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"gamecg" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"western" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.western)
|
||||
"non-h" -> Pair(SourceTagsUtil.NON_H_COLOR, R.string.non_h)
|
||||
"imageset" -> Pair(SourceTagsUtil.IMAGE_SET_COLOR, R.string.image_set)
|
||||
"cosplay" -> Pair(SourceTagsUtil.COSPLAY_COLOR, R.string.cosplay)
|
||||
"asianporn" -> Pair(SourceTagsUtil.ASIAN_PORN_COLOR, R.string.asian_porn)
|
||||
"misc" -> Pair(SourceTagsUtil.MISC_COLOR, R.string.misc)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
if (pair.first.isNotBlank()) {
|
||||
genre.setBackgroundColor(Color.parseColor(pair.first))
|
||||
genre.text = view.context.getString(pair.second)
|
||||
} else genre.text = metadata.genre
|
||||
|
||||
metadata.datePosted?.let { date_posted.text = EX_DATE_FORMAT.format(Date(it)) }
|
||||
|
||||
metadata.averageRating?.let { rating_bar.rating = it.toFloat() }
|
||||
|
||||
val locale = getLocaleSourceUtil(metadata.tags.firstOrNull { it.namespace == "language" }?.name)
|
||||
val pageCount = metadata.length
|
||||
|
||||
language.text = if (locale != null && pageCount != null) {
|
||||
view.resources.getQuantityString(R.plurals.browse_language_and_pages, pageCount, pageCount, locale.toLanguageTag().toUpperCase())
|
||||
} else if (pageCount != null) {
|
||||
view.resources.getQuantityString(R.plurals.num_pages, pageCount, pageCount)
|
||||
} else locale?.toLanguageTag()?.toUpperCase()
|
||||
}
|
||||
|
||||
override fun setImage(manga: Manga) {
|
||||
GlideApp.with(view.context).clear(thumbnail)
|
||||
|
||||
if (!manga.thumbnail_url.isNullOrEmpty()) {
|
||||
val radius = view.context.resources.getDimensionPixelSize(R.dimen.card_radius)
|
||||
val requestOptions = RequestOptions().transform(CenterCrop(), RoundedCorners(radius))
|
||||
GlideApp.with(view.context)
|
||||
.load(manga.toMangaThumbnail())
|
||||
.diskCacheStrategy(DiskCacheStrategy.DATA)
|
||||
.apply(requestOptions)
|
||||
.dontAnimate()
|
||||
.placeholder(android.R.color.transparent)
|
||||
.into(thumbnail)
|
||||
}
|
||||
}
|
||||
}
|
@ -14,25 +14,26 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
|
||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||
import kotlinx.android.synthetic.main.source_compact_grid_item.view.card
|
||||
import kotlinx.android.synthetic.main.source_compact_grid_item.view.gradient
|
||||
|
||||
class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMode>) :
|
||||
class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMode> /* SY --> */, private val metadata: RaisedSearchMetadata? = null /* SY <-- */) :
|
||||
AbstractFlexibleItem<SourceHolder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return when (displayMode.get()) {
|
||||
return /* SY --> */ if (metadata == null) /* SY <-- */ when (displayMode.get()) {
|
||||
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item
|
||||
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
|
||||
DisplayMode.LIST -> R.layout.source_list_item
|
||||
}
|
||||
} /* SY --> */ else R.layout.source_enhanced_ehentai_list_item /* SY <-- */
|
||||
}
|
||||
|
||||
override fun createViewHolder(
|
||||
view: View,
|
||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
|
||||
): SourceHolder {
|
||||
return when (displayMode.get()) {
|
||||
return /* SY --> */ if (metadata == null) /* SY <-- */ when (displayMode.get()) {
|
||||
DisplayMode.COMPACT_GRID -> {
|
||||
val parent = adapter.recyclerView as AutofitRecyclerView
|
||||
val coverHeight = parent.itemWidth / 3 * 4
|
||||
@ -59,7 +60,11 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
||||
DisplayMode.LIST -> {
|
||||
SourceListHolder(view, adapter)
|
||||
}
|
||||
// SY -->
|
||||
} else {
|
||||
SourceEnhancedEHentaiListHolder(view, adapter)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun bindViewHolder(
|
||||
@ -69,6 +74,11 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
|
||||
payloads: List<Any?>?
|
||||
) {
|
||||
holder.onSetValues(manga)
|
||||
// SY -->
|
||||
if (metadata != null) {
|
||||
(holder as? SourceEnhancedEHentaiListHolder)?.onSetMetadataValues(manga, metadata)
|
||||
}
|
||||
// SY <--
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
|
@ -20,7 +20,7 @@ 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.SourceTagsUtil.Companion.getRaisedTags
|
||||
import exh.util.makeSearchChip
|
||||
import exh.util.setChipsExtended
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -128,11 +128,11 @@ class MangaInfoItemAdapter(
|
||||
.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()
|
||||
val genre = manga.getRaisedTags()
|
||||
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) } }
|
||||
namespaceTags = genre
|
||||
.groupBy { it.namespace }
|
||||
.mapValues { values -> values.value.map { makeSearchChip(it.name, controller::performSearch, controller::performGlobalSearch, source.id, itemView.context, it.namespace) } }
|
||||
.map { NamespaceTagsItem(it.key, it.value) }
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
open class NamespaceTagsItem(val namespace: String, val tags: List<Chip>) : AbstractFlexibleItem<NamespaceTagsItem.Holder>() {
|
||||
open class NamespaceTagsItem(val namespace: String?, val tags: List<Chip>) : AbstractFlexibleItem<NamespaceTagsItem.Holder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.manga_info_genre_grouping
|
||||
@ -22,7 +22,7 @@ open class NamespaceTagsItem(val namespace: String, val tags: List<Chip>) : Abst
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val namespaceChip = Chip(holder.itemView.context)
|
||||
namespaceChip.text = namespace
|
||||
namespaceChip.text = namespace ?: holder.itemView.context.getString(R.string.unknown)
|
||||
holder.namespaceChipGroup.addView(namespaceChip)
|
||||
|
||||
tags.forEach {
|
||||
|
@ -518,6 +518,13 @@ class SettingsEhController : SettingsController() {
|
||||
|
||||
onChange { preferences.imageQuality().reconfigure() }
|
||||
}.dependency = PreferenceKeys.eh_enableExHentai
|
||||
|
||||
switchPreference {
|
||||
titleRes = R.string.pref_enhanced_e_hentai_view
|
||||
summaryRes = R.string.pref_enhanced_e_hentai_view_summary
|
||||
key = PreferenceKeys.enhancedEHentaiView
|
||||
defaultValue = true
|
||||
}
|
||||
}
|
||||
|
||||
preferenceCategory {
|
||||
|
@ -14,6 +14,7 @@ import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.humanReadableByteCount
|
||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||
import exh.ui.metadata.MetadataViewController
|
||||
import exh.util.SourceTagsUtil
|
||||
import java.util.Date
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -50,16 +51,16 @@ class EHentaiDescriptionAdapter(
|
||||
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)
|
||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"artistcg" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"gamecg" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"western" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.western)
|
||||
"non-h" -> Pair(SourceTagsUtil.NON_H_COLOR, R.string.non_h)
|
||||
"imageset" -> Pair(SourceTagsUtil.IMAGE_SET_COLOR, R.string.image_set)
|
||||
"cosplay" -> Pair(SourceTagsUtil.COSPLAY_COLOR, R.string.cosplay)
|
||||
"asianporn" -> Pair(SourceTagsUtil.ASIAN_PORN_COLOR, R.string.asian_porn)
|
||||
"misc" -> Pair(SourceTagsUtil.MISC_COLOR, R.string.misc)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
@ -80,7 +81,7 @@ class EHentaiDescriptionAdapter(
|
||||
|
||||
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)
|
||||
binding.pages.text = itemView.resources.getQuantityString(R.plurals.num_pages, meta.length ?: 0, 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)
|
||||
|
@ -41,7 +41,7 @@ class HBrowseDescriptionAdapter(
|
||||
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.pages.text = itemView.resources.getQuantityString(R.plurals.num_pages, meta.length ?: 0, meta.length ?: 0)
|
||||
|
||||
binding.moreInfo.clicks()
|
||||
.onEach {
|
||||
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.metadata.HitomiSearchMetadata
|
||||
import exh.ui.metadata.MetadataViewController
|
||||
import exh.util.SourceTagsUtil
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -47,16 +48,16 @@ class HitomiDescriptionAdapter(
|
||||
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)
|
||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"artist CG" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"game CG" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"western" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.western)
|
||||
"non-H" -> Pair(SourceTagsUtil.NON_H_COLOR, R.string.non_h)
|
||||
"image Set" -> Pair(SourceTagsUtil.IMAGE_SET_COLOR, R.string.image_set)
|
||||
"cosplay" -> Pair(SourceTagsUtil.COSPLAY_COLOR, R.string.cosplay)
|
||||
"asian Porn" -> Pair(SourceTagsUtil.ASIAN_PORN_COLOR, R.string.asian_porn)
|
||||
"misc" -> Pair(SourceTagsUtil.MISC_COLOR, R.string.misc)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import exh.metadata.EX_DATE_FORMAT
|
||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||
import exh.ui.metadata.MetadataViewController
|
||||
import exh.util.SourceTagsUtil
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -54,16 +55,16 @@ class NHentaiDescriptionAdapter(
|
||||
|
||||
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)
|
||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"artistcg" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"gamecg" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"western" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.western)
|
||||
"non-h" -> Pair(SourceTagsUtil.NON_H_COLOR, R.string.non_h)
|
||||
"imageset" -> Pair(SourceTagsUtil.IMAGE_SET_COLOR, R.string.image_set)
|
||||
"cosplay" -> Pair(SourceTagsUtil.COSPLAY_COLOR, R.string.cosplay)
|
||||
"asianporn" -> Pair(SourceTagsUtil.ASIAN_PORN_COLOR, R.string.asian_porn)
|
||||
"misc" -> Pair(SourceTagsUtil.MISC_COLOR, R.string.misc)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
@ -85,7 +86,7 @@ class NHentaiDescriptionAdapter(
|
||||
|
||||
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)
|
||||
binding.pages.text = itemView.resources.getQuantityString(R.plurals.num_pages, meta.pageImageTypes.size, meta.pageImageTypes.size)
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.id.text = "#" + (meta.nhId ?: 0)
|
||||
|
||||
|
@ -11,6 +11,7 @@ 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 exh.util.SourceTagsUtil
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -47,11 +48,11 @@ class PervEdenDescriptionAdapter(
|
||||
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)
|
||||
"Doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"Japanese Manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"Korean Manhwa" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.manhwa)
|
||||
"Chinese Manhua" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.manhua)
|
||||
"Comic" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.comic)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ 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 exh.util.SourceTagsUtil
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -47,12 +48,12 @@ class PururinDescriptionAdapter(
|
||||
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)
|
||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"artist-cg" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"game-cg" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"artbook" -> Pair(SourceTagsUtil.IMAGE_SET_COLOR, R.string.artbook)
|
||||
"webtoon" -> Pair(SourceTagsUtil.NON_H_COLOR, R.string.webtoon)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
@ -64,7 +65,7 @@ class PururinDescriptionAdapter(
|
||||
|
||||
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)
|
||||
binding.pages.text = itemView.resources.getQuantityString(R.plurals.num_pages, meta.pages ?: 0, meta.pages ?: 0)
|
||||
|
||||
val ratingFloat = meta.averageRating?.toFloat()
|
||||
val name = when (((ratingFloat ?: 100F) * 2).roundToInt()) {
|
||||
|
@ -12,6 +12,7 @@ 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 exh.util.SourceTagsUtil
|
||||
import java.util.Date
|
||||
import kotlin.math.roundToInt
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@ -48,11 +49,11 @@ class TsuminoDescriptionAdapter(
|
||||
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)
|
||||
"Doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||
"Manga" -> Pair(SourceTagsUtil.MANGA_COLOR, R.string.manga)
|
||||
"Artist CG" -> Pair(SourceTagsUtil.ARTIST_CG_COLOR, R.string.artist_cg)
|
||||
"Game CG" -> Pair(SourceTagsUtil.GAME_CG_COLOR, R.string.game_cg)
|
||||
"Video" -> Pair(SourceTagsUtil.WESTERN_COLOR, R.string.video)
|
||||
else -> Pair("", 0)
|
||||
}
|
||||
|
||||
@ -70,7 +71,7 @@ class TsuminoDescriptionAdapter(
|
||||
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)
|
||||
binding.pages.text = itemView.resources.getQuantityString(R.plurals.num_pages, meta.length ?: 0, meta.length ?: 0)
|
||||
|
||||
val name = when (((meta.averageRating ?: 100F) * 2).roundToInt()) {
|
||||
0 -> R.string.rating0
|
||||
|
@ -1,30 +1,31 @@
|
||||
package exh.util
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.HITOMI_SOURCE_ID
|
||||
import exh.NHENTAI_SOURCE_ID
|
||||
import exh.PURURIN_SOURCE_ID
|
||||
import exh.TSUMINO_SOURCE_ID
|
||||
import exh.metadata.metadata.base.RaisedTag
|
||||
import java.util.Locale
|
||||
|
||||
class SourceTagsUtil {
|
||||
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
||||
return if (sourceId == EXH_SOURCE_ID || sourceId == EH_SOURCE_ID || sourceId == NHENTAI_SOURCE_ID || sourceId == HITOMI_SOURCE_ID) {
|
||||
val parsed = if (fullTag != null) parseTag(fullTag) else if (namespace != null && tag != null) Pair(namespace, tag) else null
|
||||
if (parsed != null) {
|
||||
val parsed = if (fullTag != null) parseTag(fullTag) else if (namespace != null && tag != null) RaisedTag(namespace, tag, TAG_TYPE_DEFAULT) else null
|
||||
if (parsed?.namespace != null) {
|
||||
when (sourceId) {
|
||||
HITOMI_SOURCE_ID -> wrapTagHitomi(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
PURURIN_SOURCE_ID -> parsed.second.substringBefore('|').trim()
|
||||
TSUMINO_SOURCE_ID -> parsed.second.substringBefore('|').trim()
|
||||
else -> wrapTag(parsed.first, parsed.second.substringBefore('|').trim())
|
||||
HITOMI_SOURCE_ID -> wrapTagHitomi(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
PURURIN_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||
TSUMINO_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||
else -> wrapTag(parsed.namespace, parsed.name.substringBefore('|').trim())
|
||||
}
|
||||
} else null
|
||||
} else null
|
||||
}
|
||||
|
||||
fun parseTag(tag: String) = tag.substringBefore(':').trim() to tag.substringAfter(':').trim()
|
||||
|
||||
private fun wrapTag(namespace: String, tag: String) = if (tag.contains(' ')) {
|
||||
"$namespace:\"$tag$\""
|
||||
} else {
|
||||
@ -46,4 +47,40 @@ class SourceTagsUtil {
|
||||
} else {
|
||||
"$namespace:$tag"
|
||||
}
|
||||
companion object {
|
||||
fun Manga.getRaisedTags(): List<RaisedTag>? = this.getGenres()?.map { parseTag(it) }
|
||||
|
||||
fun parseTag(tag: String) = RaisedTag(tag.substringBefore(':').trimOrNull(), (tag.substringAfter(':').trimOrNull() ?: tag), TAG_TYPE_DEFAULT)
|
||||
|
||||
const val DOUJINSHI_COLOR = "#f44336"
|
||||
const val MANGA_COLOR = "#ff9800"
|
||||
const val ARTIST_CG_COLOR = "#fbc02d"
|
||||
const val GAME_CG_COLOR = "#4caf50"
|
||||
const val WESTERN_COLOR = "#8bc34a"
|
||||
const val NON_H_COLOR = "#2196f3"
|
||||
const val IMAGE_SET_COLOR = "#3f51b5"
|
||||
const val COSPLAY_COLOR = "#9c27b0"
|
||||
const val ASIAN_PORN_COLOR = "#9575cd"
|
||||
const val MISC_COLOR = "#f06292"
|
||||
|
||||
fun getLocaleSourceUtil(language: String?) = when (language) {
|
||||
"english", "eng" -> Locale("en")
|
||||
"chinese" -> Locale("zh")
|
||||
"spanish" -> Locale("es")
|
||||
"korean" -> Locale("ko")
|
||||
"russian" -> Locale("ru")
|
||||
"french" -> Locale("fr")
|
||||
"portuguese" -> Locale("pt")
|
||||
"thai" -> Locale("th")
|
||||
"german" -> Locale("de")
|
||||
"italian" -> Locale("it")
|
||||
"vietnamese" -> Locale("vi")
|
||||
"polish" -> Locale("pl")
|
||||
"hungarian" -> Locale("hu")
|
||||
"dutch" -> Locale("nl")
|
||||
else -> null
|
||||
}
|
||||
|
||||
private const val TAG_TYPE_DEFAULT = 1
|
||||
}
|
||||
}
|
||||
|
106
app/src/main/res/layout/source_enhanced_ehentai_list_item.xml
Normal file
106
app/src/main/res/layout/source_enhanced_ehentai_list_item.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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="140dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:background="@drawable/list_item_selector"
|
||||
android:paddingEnd="8dp"
|
||||
tools:layout_editor_absoluteX="0dp"
|
||||
tools:layout_editor_absoluteY="25dp">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="140dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@mipmap/ic_launcher" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.Regular.SubHeading"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/thumbnail"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Manga title for the life of me I cant think yes totally" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/uploader"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/thumbnail"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
tools:text="Manga title for the life of me I cant think yes totally" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/cardView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@drawable/rounded_rectangle"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/thumbnail">
|
||||
|
||||
<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:maxLines="1"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="4dp" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<me.zhanghai.android.materialratingbar.MaterialRatingBar
|
||||
android:id="@+id/rating_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:isIndicator="true"
|
||||
android:maxHeight="20dp"
|
||||
android:minHeight="20dp"
|
||||
android:numStars="5"
|
||||
app:layout_constraintBottom_toTopOf="@+id/cardView"
|
||||
app:layout_constraintStart_toEndOf="@+id/thumbnail" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/date_posted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/language"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintBottom_toTopOf="@+id/date_posted"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -10,6 +10,7 @@
|
||||
app:showAsAction="collapseActionView|ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_display_mode"
|
||||
android:icon="@drawable/ic_view_module_24dp"
|
||||
android:title="@string/action_display_mode"
|
||||
app:iconTint="?attr/colorOnPrimary"
|
||||
|
@ -71,6 +71,8 @@
|
||||
<string name="eh_image_quality_1280">1280x</string>
|
||||
<string name="eh_image_quality_980">980x</string>
|
||||
<string name="eh_image_quality_780">780x</string>
|
||||
<string name="pref_enhanced_e_hentai_view">Enhanced E/ExHentai browse</string>
|
||||
<string name="pref_enhanced_e_hentai_view_summary">Enable/Disable the enhanced browse menu made for E/ExHentai</string>
|
||||
<string name="favorites_sync">Favorites sync</string>
|
||||
<string name="disable_favorites_uploading">Disable favorites uploading</string>
|
||||
<string name="disable_favorites_uploading_summary">Favorites are only downloaded from ExHentai. Any changes to favorites in the app will not be uploaded. Prevents accidental loss of favorites on ExHentai. Note that removals will still be downloaded (if you remove a favorites on ExHentai, it will be removed in the app as well).</string>
|
||||
@ -414,11 +416,21 @@
|
||||
<string name="parodies">Parodies</string>
|
||||
|
||||
<!-- Extra gallery info -->
|
||||
<string name="num_pages">%1$d pages</string>
|
||||
<plurals name="num_pages">
|
||||
<item quantity="one">%1$d page</item>
|
||||
<item quantity="other">%1$d pages</item>
|
||||
</plurals>
|
||||
<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>
|
||||
|
||||
<!-- Enhanced E/ExHentai Browse View -->
|
||||
<plurals name="browse_language_and_pages">
|
||||
<item quantity="one">%2$s, %1$d page</item>
|
||||
<item quantity="other">%2$s, %1$d pages</item>
|
||||
</plurals>
|
||||
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user