Extract source api from app module (#8014)
* Extract source api from app module * Extract source online api from app module (cherry picked from commit 86fe85079413f8ed6e1109b46e6131a9b788b988) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt # core/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt # source-api/src/main/java/eu/kanade/tachiyomi/source/Source.kt # source-api/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt
This commit is contained in:
parent
b975b9b86f
commit
8a322ea28e
@ -133,6 +133,8 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":i18n"))
|
implementation(project(":i18n"))
|
||||||
|
implementation(project(":core"))
|
||||||
|
implementation(project(":source-api"))
|
||||||
|
|
||||||
// Compose
|
// Compose
|
||||||
implementation(compose.activity)
|
implementation(compose.activity)
|
||||||
|
@ -20,6 +20,7 @@ import eu.kanade.domain.manga.interactor.GetExhFavoriteMangaWithMetadata
|
|||||||
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
import eu.kanade.domain.manga.interactor.GetFavoriteEntries
|
||||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
||||||
import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
import eu.kanade.domain.manga.interactor.GetIdsOfFavoriteMangaWithMetadata
|
||||||
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
import eu.kanade.domain.manga.interactor.GetMangaBySource
|
||||||
import eu.kanade.domain.manga.interactor.GetMergedManga
|
import eu.kanade.domain.manga.interactor.GetMergedManga
|
||||||
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
import eu.kanade.domain.manga.interactor.GetMergedMangaById
|
||||||
@ -65,6 +66,7 @@ import eu.kanade.domain.source.interactor.ToggleExcludeFromDataSaver
|
|||||||
import eu.kanade.domain.source.interactor.ToggleSources
|
import eu.kanade.domain.source.interactor.ToggleSources
|
||||||
import eu.kanade.domain.source.repository.FeedSavedSearchRepository
|
import eu.kanade.domain.source.repository.FeedSavedSearchRepository
|
||||||
import eu.kanade.domain.source.repository.SavedSearchRepository
|
import eu.kanade.domain.source.repository.SavedSearchRepository
|
||||||
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import uy.kohesive.injekt.api.InjektModule
|
import uy.kohesive.injekt.api.InjektModule
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
import uy.kohesive.injekt.api.InjektRegistrar
|
||||||
import uy.kohesive.injekt.api.addFactory
|
import uy.kohesive.injekt.api.addFactory
|
||||||
@ -100,6 +102,11 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { ReorderSortTag(get(), get()) }
|
addFactory { ReorderSortTag(get(), get()) }
|
||||||
addFactory { GetPagePreviews(get()) }
|
addFactory { GetPagePreviews(get()) }
|
||||||
|
|
||||||
|
// Required for [MetadataSource]
|
||||||
|
addFactory<MetadataSource.GetMangaId> { GetManga(get()) }
|
||||||
|
addFactory<MetadataSource.GetFlatMetadataById> { GetFlatMetadataById(get()) }
|
||||||
|
addFactory<MetadataSource.InsertFlatMetadata> { InsertFlatMetadata(get()) }
|
||||||
|
|
||||||
addSingletonFactory<MangaMetadataRepository> { MangaMetadataRepositoryImpl(get()) }
|
addSingletonFactory<MangaMetadataRepository> { MangaMetadataRepositoryImpl(get()) }
|
||||||
addFactory { GetFlatMetadataById(get()) }
|
addFactory { GetFlatMetadataById(get()) }
|
||||||
addFactory { InsertFlatMetadata(get()) }
|
addFactory { InsertFlatMetadata(get()) }
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
||||||
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@ -9,9 +10,9 @@ import logcat.LogPriority
|
|||||||
|
|
||||||
class GetFlatMetadataById(
|
class GetFlatMetadataById(
|
||||||
private val mangaMetadataRepository: MangaMetadataRepository,
|
private val mangaMetadataRepository: MangaMetadataRepository,
|
||||||
) {
|
) : MetadataSource.GetFlatMetadataById {
|
||||||
|
|
||||||
suspend fun await(id: Long): FlatMetadata? {
|
override suspend fun await(id: Long): FlatMetadata? {
|
||||||
return try {
|
return try {
|
||||||
val meta = mangaMetadataRepository.getMetadataById(id)
|
val meta = mangaMetadataRepository.getMetadataById(id)
|
||||||
return if (meta != null) {
|
return if (meta != null) {
|
||||||
|
@ -2,13 +2,14 @@ package eu.kanade.domain.manga.interactor
|
|||||||
|
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.domain.manga.repository.MangaRepository
|
import eu.kanade.domain.manga.repository.MangaRepository
|
||||||
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
|
||||||
class GetManga(
|
class GetManga(
|
||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
) {
|
) : MetadataSource.GetMangaId {
|
||||||
|
|
||||||
suspend fun await(id: Long): Manga? {
|
suspend fun await(id: Long): Manga? {
|
||||||
return try {
|
return try {
|
||||||
@ -30,4 +31,10 @@ class GetManga(
|
|||||||
fun subscribe(url: String, sourceId: Long): Flow<Manga?> {
|
fun subscribe(url: String, sourceId: Long): Flow<Manga?> {
|
||||||
return mangaRepository.getMangaByUrlAndSourceIdAsFlow(url, sourceId)
|
return mangaRepository.getMangaByUrlAndSourceIdAsFlow(url, sourceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
override suspend fun awaitId(url: String, sourceId: Long): Long? {
|
||||||
|
return await(url, sourceId)?.id
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.domain.manga.interactor
|
package eu.kanade.domain.manga.interactor
|
||||||
|
|
||||||
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
import eu.kanade.domain.manga.repository.MangaMetadataRepository
|
||||||
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import exh.metadata.metadata.base.FlatMetadata
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
@ -8,7 +9,7 @@ import logcat.LogPriority
|
|||||||
|
|
||||||
class InsertFlatMetadata(
|
class InsertFlatMetadata(
|
||||||
private val mangaMetadataRepository: MangaMetadataRepository,
|
private val mangaMetadataRepository: MangaMetadataRepository,
|
||||||
) {
|
) : MetadataSource.InsertFlatMetadata {
|
||||||
|
|
||||||
suspend fun await(flatMetadata: FlatMetadata) {
|
suspend fun await(flatMetadata: FlatMetadata) {
|
||||||
try {
|
try {
|
||||||
@ -18,7 +19,7 @@ class InsertFlatMetadata(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun await(metadata: RaisedSearchMetadata) {
|
override suspend fun await(metadata: RaisedSearchMetadata) {
|
||||||
try {
|
try {
|
||||||
mangaMetadataRepository.insertMetadata(metadata)
|
mangaMetadataRepository.insertMetadata(metadata)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
@ -72,14 +72,33 @@ import eu.kanade.presentation.util.isScrollingUp
|
|||||||
import eu.kanade.presentation.util.plus
|
import eu.kanade.presentation.util.plus
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.getNameForMangaInfo
|
import eu.kanade.tachiyomi.source.getNameForMangaInfo
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.Hitomi
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||||
|
import eu.kanade.tachiyomi.source.online.all.PervEden
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.EightMuses
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.HBrowse
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.Pururin
|
||||||
|
import eu.kanade.tachiyomi.source.online.english.Tsumino
|
||||||
import eu.kanade.tachiyomi.ui.manga.ChapterItem
|
import eu.kanade.tachiyomi.ui.manga.ChapterItem
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.ui.manga.PagePreviewState
|
import eu.kanade.tachiyomi.ui.manga.PagePreviewState
|
||||||
import exh.source.MERGED_SOURCE_ID
|
import exh.source.MERGED_SOURCE_ID
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
|
import exh.ui.metadata.adapters.EHentaiDescription
|
||||||
|
import exh.ui.metadata.adapters.EightMusesDescription
|
||||||
|
import exh.ui.metadata.adapters.HBrowseDescription
|
||||||
|
import exh.ui.metadata.adapters.HitomiDescription
|
||||||
|
import exh.ui.metadata.adapters.MangaDexDescription
|
||||||
|
import exh.ui.metadata.adapters.NHentaiDescription
|
||||||
|
import exh.ui.metadata.adapters.PervEdenDescription
|
||||||
|
import exh.ui.metadata.adapters.PururinDescription
|
||||||
|
import exh.ui.metadata.adapters.TsuminoDescription
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaScreen(
|
fun MangaScreen(
|
||||||
@ -255,7 +274,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
|
|
||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters.toList() }
|
||||||
// SY -->
|
// SY -->
|
||||||
val metadataSource = remember(state.source.id) { state.source.getMainSource<MetadataSource<*, *>>() }
|
val metadataDescription = metadataDescription(state.source)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val internalOnBackPressed = {
|
val internalOnBackPressed = {
|
||||||
@ -408,12 +427,12 @@ private fun MangaScreenSmallImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (metadataSource != null) {
|
if (metadataDescription != null) {
|
||||||
item(
|
item(
|
||||||
key = MangaScreenItem.METADATA_INFO,
|
key = MangaScreenItem.METADATA_INFO,
|
||||||
contentType = MangaScreenItem.METADATA_INFO,
|
contentType = MangaScreenItem.METADATA_INFO,
|
||||||
) {
|
) {
|
||||||
metadataSource.DescriptionComposable(
|
metadataDescription(
|
||||||
state = state,
|
state = state,
|
||||||
openMetadataViewer = onMetadataViewerClicked,
|
openMetadataViewer = onMetadataViewerClicked,
|
||||||
search = { onSearch(it, false) },
|
search = { onSearch(it, false) },
|
||||||
@ -540,7 +559,7 @@ fun MangaScreenLargeImpl(
|
|||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters.toList() }
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val metadataSource = remember(state.source.id) { state.source.getMainSource<MetadataSource<*, *>>() }
|
val metadataDescription = metadataDescription(state.source)
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||||
@ -681,7 +700,7 @@ fun MangaScreenLargeImpl(
|
|||||||
// SY <--
|
// SY <--
|
||||||
)
|
)
|
||||||
// SY -->
|
// SY -->
|
||||||
metadataSource?.DescriptionComposable(
|
metadataDescription?.invoke(
|
||||||
state = state,
|
state = state,
|
||||||
openMetadataViewer = onMetadataViewerClicked,
|
openMetadataViewer = onMetadataViewerClicked,
|
||||||
search = { onSearch(it, false) },
|
search = { onSearch(it, false) },
|
||||||
@ -847,3 +866,42 @@ private fun onChapterItemClick(
|
|||||||
else -> onChapterClicked(chapterItem.chapter)
|
else -> onChapterClicked(chapterItem.chapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typealias MetadataDescriptionComposable = @Composable (state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) -> Unit
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun metadataDescription(source: Source): MetadataDescriptionComposable? {
|
||||||
|
val metadataSource = remember(source.id) { source.getMainSource<MetadataSource<*, *>>() }
|
||||||
|
return remember(metadataSource) {
|
||||||
|
when (metadataSource) {
|
||||||
|
is EHentai -> { state, openMetadataViewer, search ->
|
||||||
|
EHentaiDescription(state, openMetadataViewer, search)
|
||||||
|
}
|
||||||
|
is Hitomi -> { state, openMetadataViewer, _ ->
|
||||||
|
HitomiDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is MangaDex -> { state, openMetadataViewer, _ ->
|
||||||
|
MangaDexDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is NHentai -> { state, openMetadataViewer, _ ->
|
||||||
|
NHentaiDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is PervEden -> { state, openMetadataViewer, _ ->
|
||||||
|
PervEdenDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is EightMuses -> { state, openMetadataViewer, _ ->
|
||||||
|
EightMusesDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is HBrowse -> { state, openMetadataViewer, _ ->
|
||||||
|
HBrowseDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is Pururin -> { state, openMetadataViewer, _ ->
|
||||||
|
PururinDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
is Tsumino -> { state, openMetadataViewer, _ ->
|
||||||
|
TsuminoDescription(state, openMetadataViewer)
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -48,6 +48,7 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.source.model.copyFrom
|
||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import eu.kanade.tachiyomi.util.system.toLong
|
import eu.kanade.tachiyomi.util.system.toLong
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.data.database.models
|
package eu.kanade.tachiyomi.data.database.models
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
open class MangaImpl : Manga {
|
open class MangaImpl : Manga {
|
||||||
@ -77,6 +81,19 @@ open class MangaImpl : Manga {
|
|||||||
private set
|
private set
|
||||||
var ogStatus: Int = 0
|
var ogStatus: Int = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
override val originalTitle: String
|
||||||
|
get() = ogTitle
|
||||||
|
override val originalAuthor: String?
|
||||||
|
get() = ogAuthor ?: author
|
||||||
|
override val originalArtist: String?
|
||||||
|
get() = ogArtist ?: artist
|
||||||
|
override val originalDescription: String?
|
||||||
|
get() = ogDesc ?: description
|
||||||
|
override val originalGenre: String?
|
||||||
|
get() = ogGenre ?: genre
|
||||||
|
override val originalStatus: Int
|
||||||
|
get() = ogStatus
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
@ -93,6 +110,18 @@ open class MangaImpl : Manga {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
|
override fun copyFrom(other: SManga) {
|
||||||
|
// EXH -->
|
||||||
|
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||||
|
val source = (this as? Manga)?.source
|
||||||
|
if (source != null) {
|
||||||
|
Injekt.get<DownloadManager>().renameMangaDir(originalTitle, other.originalTitle, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// EXH <--
|
||||||
|
super.copyFrom(other)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerConfig
|
|||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
import eu.kanade.tachiyomi.util.system.isDevFlavor
|
||||||
|
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package eu.kanade.tachiyomi.source
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import eu.kanade.domain.source.model.SourceData
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
||||||
|
|
||||||
|
fun Source.getPreferenceKey(): String = "source_$id"
|
||||||
|
|
||||||
|
fun Source.toSourceData(): SourceData = SourceData(id = id, lang = lang, name = name)
|
||||||
|
|
||||||
|
fun Source.getNameForMangaInfo(mergeSources: List<Source>?): String {
|
||||||
|
val preferences = Injekt.get<PreferencesHelper>()
|
||||||
|
val enabledLanguages = preferences.enabledLanguages().get()
|
||||||
|
.filterNot { it in listOf("all", "other") }
|
||||||
|
val hasOneActiveLanguages = enabledLanguages.size == 1
|
||||||
|
val isInEnabledLanguages = lang in enabledLanguages
|
||||||
|
return when {
|
||||||
|
// SY -->
|
||||||
|
!mergeSources.isNullOrEmpty() -> getMergedSourcesString(
|
||||||
|
mergeSources,
|
||||||
|
enabledLanguages,
|
||||||
|
hasOneActiveLanguages,
|
||||||
|
)
|
||||||
|
// SY <--
|
||||||
|
// For edge cases where user disables a source they got manga of in their library.
|
||||||
|
hasOneActiveLanguages && !isInEnabledLanguages -> toString()
|
||||||
|
// Hide the language tag when only one language is used.
|
||||||
|
hasOneActiveLanguages && isInEnabledLanguages -> name
|
||||||
|
else -> toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
private fun getMergedSourcesString(
|
||||||
|
mergeSources: List<Source>,
|
||||||
|
enabledLangs: List<String>,
|
||||||
|
onlyName: Boolean,
|
||||||
|
): String {
|
||||||
|
return if (onlyName) {
|
||||||
|
mergeSources.joinToString { source ->
|
||||||
|
if (source.lang !in enabledLangs) {
|
||||||
|
source.toString()
|
||||||
|
} else {
|
||||||
|
source.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mergeSources.joinToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
|
|
||||||
|
fun Source.isLocalOrStub(): Boolean = id == LocalSource.ID || this is SourceManager.StubSource
|
@ -133,6 +133,7 @@ class SourceManager(
|
|||||||
val enhancedSource = EnhancedHttpSource(
|
val enhancedSource = EnhancedHttpSource(
|
||||||
this,
|
this,
|
||||||
delegate.newSourceClass.constructors.find { it.parameters.size == 2 }!!.call(this, context),
|
delegate.newSourceClass.constructors.find { it.parameters.size == 2 }!!.call(this, context),
|
||||||
|
::delegateSources,
|
||||||
)
|
)
|
||||||
|
|
||||||
currentDelegatedSources[enhancedSource.originalSource.id] = DelegatedSource(
|
currentDelegatedSources[enhancedSource.originalSource.id] = DelegatedSource(
|
||||||
@ -156,6 +157,8 @@ class SourceManager(
|
|||||||
// EXH <--
|
// EXH <--
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun delegateSources() = preferences.delegateSources().get()
|
||||||
|
|
||||||
fun get(sourceKey: Long): Source? {
|
fun get(sourceKey: Long): Source? {
|
||||||
return sourcesMap[sourceKey]
|
return sourcesMap[sourceKey]
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package eu.kanade.tachiyomi.source.model
|
||||||
|
|
||||||
|
import data.Chapters
|
||||||
|
|
||||||
|
fun SChapter.copyFrom(other: Chapters) {
|
||||||
|
name = other.name
|
||||||
|
url = other.url
|
||||||
|
date_upload = other.date_upload
|
||||||
|
chapter_number = other.chapter_number
|
||||||
|
scanlator = other.scanlator
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package eu.kanade.tachiyomi.source.model
|
||||||
|
|
||||||
|
import data.Mangas
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
fun SManga.copyFrom(other: Mangas) {
|
||||||
|
// EXH -->
|
||||||
|
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||||
|
val oldTitle = originalTitle
|
||||||
|
title = other.title
|
||||||
|
val source = (this as? Manga)?.source
|
||||||
|
if (source != null) {
|
||||||
|
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.title, source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// EXH <--
|
||||||
|
|
||||||
|
if (other.author != null) {
|
||||||
|
author = other.author
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.artist != null) {
|
||||||
|
artist = other.artist
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.description != null) {
|
||||||
|
description = other.description
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.genre != null) {
|
||||||
|
genre = other.genre.joinToString(separator = ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other.thumbnail_url != null) {
|
||||||
|
thumbnail_url = other.thumbnail_url
|
||||||
|
}
|
||||||
|
|
||||||
|
status = other.status.toInt()
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
initialized = other.initialized
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
|
||||||
|
|
||||||
interface BrowseSourceFilterHeader : CatalogueSource {
|
|
||||||
fun getFilterHeader(controller: BaseController<*>, onClick: () -> Unit): RecyclerView.Adapter<*>
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
@ -28,7 +27,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
@ -51,7 +49,6 @@ import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUA
|
|||||||
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.toGenreString
|
import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.toGenreString
|
||||||
import exh.metadata.metadata.base.RaisedTag
|
import exh.metadata.metadata.base.RaisedTag
|
||||||
import exh.ui.login.EhLoginActivity
|
import exh.ui.login.EhLoginActivity
|
||||||
import exh.ui.metadata.adapters.EHentaiDescription
|
|
||||||
import exh.util.UriFilter
|
import exh.util.UriFilter
|
||||||
import exh.util.UriGroup
|
import exh.util.UriGroup
|
||||||
import exh.util.asObservableWithAsyncStacktrace
|
import exh.util.asObservableWithAsyncStacktrace
|
||||||
@ -1127,11 +1124,6 @@ class EHentai(
|
|||||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${obj["token"]!!.jsonPrimitive.content}/"
|
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${obj["token"]!!.jsonPrimitive.content}/"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
EHentaiDescription(state, openMetadataViewer, search)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getPagePreviewList(
|
override suspend fun getPagePreviewList(
|
||||||
manga: SManga,
|
manga: SManga,
|
||||||
page: Int,
|
page: Int,
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
@ -11,13 +10,11 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.HitomiSearchMetadata
|
import exh.metadata.metadata.HitomiSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
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.HitomiDescription
|
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -136,11 +133,6 @@ class Hitomi(delegate: HttpSource, val context: Context) :
|
|||||||
return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html"
|
return "https://hitomi.la/manga/${uri.pathSegments[1].substringBefore('.')}.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
HitomiDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val otherId = 2703068117101782422L
|
const val otherId = 2703068117101782422L
|
||||||
private val DATE_FORMAT by lazy {
|
private val DATE_FORMAT by lazy {
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
@ -14,7 +13,6 @@ import eu.kanade.tachiyomi.source.model.MetadataMangasPage
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
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.source.online.BrowseSourceFilterHeader
|
|
||||||
import eu.kanade.tachiyomi.source.online.FollowsSource
|
import eu.kanade.tachiyomi.source.online.FollowsSource
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.source.online.LoginSource
|
import eu.kanade.tachiyomi.source.online.LoginSource
|
||||||
@ -22,10 +20,7 @@ import eu.kanade.tachiyomi.source.online.MetadataSource
|
|||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.RandomMangaSource
|
import eu.kanade.tachiyomi.source.online.RandomMangaSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||||
import exh.md.MangaDexFabHeaderAdapter
|
|
||||||
import exh.md.dto.MangaDto
|
import exh.md.dto.MangaDto
|
||||||
import exh.md.dto.StatisticsMangaDto
|
import exh.md.dto.StatisticsMangaDto
|
||||||
import exh.md.handlers.ApiMangaParser
|
import exh.md.handlers.ApiMangaParser
|
||||||
@ -49,7 +44,6 @@ import exh.md.utils.MdLang
|
|||||||
import exh.md.utils.MdUtil
|
import exh.md.utils.MdUtil
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
import exh.ui.metadata.adapters.MangaDexDescription
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
@ -64,7 +58,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
UrlImportableSource,
|
UrlImportableSource,
|
||||||
FollowsSource,
|
FollowsSource,
|
||||||
LoginSource,
|
LoginSource,
|
||||||
BrowseSourceFilterHeader,
|
|
||||||
RandomMangaSource,
|
RandomMangaSource,
|
||||||
NamespaceSource {
|
NamespaceSource {
|
||||||
override val lang: String = delegate.lang
|
override val lang: String = delegate.lang
|
||||||
@ -217,11 +210,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
// MetadataSource methods
|
// MetadataSource methods
|
||||||
override val metaClass: KClass<MangaDexSearchMetadata> = MangaDexSearchMetadata::class
|
override val metaClass: KClass<MangaDexSearchMetadata> = MangaDexSearchMetadata::class
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
MangaDexDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Triple<MangaDto, List<String>, StatisticsMangaDto>) {
|
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Triple<MangaDto, List<String>, StatisticsMangaDto>) {
|
||||||
apiMangaParser.parseIntoMetadata(metadata, input.first, input.second, input.third)
|
apiMangaParser.parseIntoMetadata(metadata, input.first, input.second, input.third)
|
||||||
}
|
}
|
||||||
@ -272,11 +260,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
return followsHandler.fetchAllFollows()
|
return followsHandler.fetchAllFollows()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
|
||||||
return followsHandler.updateFollowStatus(mangaID, followStatus)
|
return followsHandler.updateFollowStatus(mangaID, followStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchTrackingInfo(url: String): Track {
|
suspend fun fetchTrackingInfo(url: String): Track {
|
||||||
return followsHandler.fetchTrackingInfo(url)
|
return followsHandler.fetchTrackingInfo(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,11 +281,6 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
|||||||
return mangaHandler.getTrackingInfo(track)
|
return mangaHandler.getTrackingInfo(track)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BrowseSourceFilterHeader method
|
|
||||||
override fun getFilterHeader(controller: BaseController<*>, onClick: () -> Unit): MangaDexFabHeaderAdapter {
|
|
||||||
return MangaDexFabHeaderAdapter(controller, this, onClick)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RandomMangaSource method
|
// RandomMangaSource method
|
||||||
override suspend fun fetchRandomMangaUrl(): String {
|
override suspend fun fetchRandomMangaUrl(): String {
|
||||||
return mangaHandler.fetchRandomMangaId()
|
return mangaHandler.fetchRandomMangaId()
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.newCallWithProgress
|
import eu.kanade.tachiyomi.network.newCallWithProgress
|
||||||
@ -16,12 +15,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
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.NHentaiDescription
|
|
||||||
import exh.util.trimOrNull
|
import exh.util.trimOrNull
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
@ -175,11 +172,6 @@ class NHentai(delegate: HttpSource, val context: Context) :
|
|||||||
return "$baseUrl/g/${uri.pathSegments[1]}/"
|
return "$baseUrl/g/${uri.pathSegments[1]}/"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
NHentaiDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getPagePreviewList(manga: SManga, page: Int): PagePreviewPage {
|
override suspend fun getPagePreviewList(manga: SManga, page: Int): PagePreviewPage {
|
||||||
val metadata = fetchOrLoadMetadata(manga.id()) {
|
val metadata = fetchOrLoadMetadata(manga.id()) {
|
||||||
client.newCall(mangaDetailsRequest(manga)).await()
|
client.newCall(mangaDetailsRequest(manga)).await()
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -10,13 +9,11 @@ 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.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.PervEdenSearchMetadata
|
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
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.PervEdenDescription
|
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -132,9 +129,4 @@ class PervEden(delegate: HttpSource, val context: Context) :
|
|||||||
}
|
}
|
||||||
return newUri.toString()
|
return newUri.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
PervEdenDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -11,12 +10,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.EightMusesSearchMetadata
|
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||||
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.EightMusesDescription
|
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -96,9 +93,4 @@ class EightMuses(delegate: HttpSource, val context: Context) :
|
|||||||
}
|
}
|
||||||
return "/comics/album/${path.joinToString("/")}"
|
return "/comics/album/${path.joinToString("/")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
EightMusesDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
@ -10,12 +9,10 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import exh.metadata.metadata.HBrowseSearchMetadata
|
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||||
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.HBrowseDescription
|
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
@ -84,9 +81,4 @@ class HBrowse(delegate: HttpSource, val context: Context) :
|
|||||||
override suspend fun mapUrlToMangaUrl(uri: Uri): String? {
|
override suspend fun mapUrlToMangaUrl(uri: Uri): String? {
|
||||||
return uri.pathSegments.firstOrNull()?.let { "/$it/c00001/" }
|
return uri.pathSegments.firstOrNull()?.let { "/$it/c00001/" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
HBrowseDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
@ -12,13 +11,11 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
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
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
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.PururinDescription
|
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.trimAll
|
import exh.util.trimAll
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -116,9 +113,4 @@ class Pururin(delegate: HttpSource, val context: Context) :
|
|||||||
override suspend fun mapUrlToMangaUrl(uri: Uri): String {
|
override suspend fun mapUrlToMangaUrl(uri: Uri): String {
|
||||||
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments.getOrNull(1)}/${uri.lastPathSegment}"
|
return "${PururinSearchMetadata.BASE_URL}/gallery/${uri.pathSegments.getOrNull(1)}/${uri.lastPathSegment}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
PururinDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.source.online.english
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
@ -11,14 +10,12 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.source.online.MetadataSource
|
import eu.kanade.tachiyomi.source.online.MetadataSource
|
||||||
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
import eu.kanade.tachiyomi.source.online.NamespaceSource
|
||||||
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
import eu.kanade.tachiyomi.source.online.UrlImportableSource
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
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.TsuminoDescription
|
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.trimAll
|
import exh.util.trimAll
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
@ -141,9 +138,4 @@ class Tsumino(delegate: HttpSource, val context: Context) :
|
|||||||
val RATING_USERS_REGEX = "\\(([0-9].*) users".toRegex()
|
val RATING_USERS_REGEX = "\\(([0-9].*) users".toRegex()
|
||||||
val RATING_FAVORITES_REGEX = "/ ([0-9].*) favs".toRegex()
|
val RATING_FAVORITES_REGEX = "/ ([0-9].*) favs".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
override fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
|
||||||
TsuminoDescription(state, openMetadataViewer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,11 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
|
|||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
|
import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.online.BrowseSourceFilterHeader
|
import eu.kanade.tachiyomi.source.online.all.MangaDex
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
import eu.kanade.tachiyomi.ui.base.controller.BaseController
|
||||||
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
||||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
||||||
|
import exh.md.MangaDexFabHeaderAdapter
|
||||||
import exh.savedsearches.EXHSavedSearch
|
import exh.savedsearches.EXHSavedSearch
|
||||||
import exh.source.getMainSource
|
import exh.source.getMainSource
|
||||||
|
|
||||||
@ -117,8 +118,12 @@ class SourceFilterSheet(
|
|||||||
recycler.adapter = ConcatAdapter(
|
recycler.adapter = ConcatAdapter(
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
controller?.let {
|
controller?.let {
|
||||||
source?.getMainSource<BrowseSourceFilterHeader>()
|
source?.getMainSource<MangaDex>()
|
||||||
?.getFilterHeader(it) { dismissSheet?.invoke() }
|
?.let {
|
||||||
|
MangaDexFabHeaderAdapter(controller, it) {
|
||||||
|
dismissSheet?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
savedSearchesAdapter,
|
savedSearchesAdapter,
|
||||||
adapter,
|
adapter,
|
||||||
|
@ -46,7 +46,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem<
|
|||||||
// select from auto complete
|
// select from auto complete
|
||||||
holder.autoComplete.setOnItemClickListener { adapterView, _, chipPosition, _ ->
|
holder.autoComplete.setOnItemClickListener { adapterView, _, chipPosition, _ ->
|
||||||
val name = adapterView.getItemAtPosition(chipPosition) as String
|
val name = adapterView.getItemAtPosition(chipPosition) as String
|
||||||
if (name !in if (filter.excludePrefix != null && name.startsWith(filter.excludePrefix)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
if (name !in if (filter.excludePrefix != null && name.startsWith(filter.excludePrefix!!)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||||
holder.autoComplete.text = null
|
holder.autoComplete.text = null
|
||||||
addTag(name, holder)
|
addTag(name, holder)
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem<
|
|||||||
|
|
||||||
// done keyboard button is pressed
|
// done keyboard button is pressed
|
||||||
holder.autoComplete.setOnEditorActionListener { textView, actionId, _ ->
|
holder.autoComplete.setOnEditorActionListener { textView, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE && textView.text.toString() !in if (filter.excludePrefix != null && textView.text.toString().startsWith(filter.excludePrefix)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
if (actionId == EditorInfo.IME_ACTION_DONE && textView.text.toString() !in if (filter.excludePrefix != null && textView.text.toString().startsWith(filter.excludePrefix!!)) filter.skipAutoFillTags.map { filter.excludePrefix + it } else filter.skipAutoFillTags) {
|
||||||
textView.text = null
|
textView.text = null
|
||||||
addTag(textView.text.toString(), holder)
|
addTag(textView.text.toString(), holder)
|
||||||
return@setOnEditorActionListener true
|
return@setOnEditorActionListener true
|
||||||
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
|
|||||||
import eu.kanade.tachiyomi.util.preference.switchPreference
|
import eu.kanade.tachiyomi.util.preference.switchPreference
|
||||||
import eu.kanade.tachiyomi.util.preference.titleRes
|
import eu.kanade.tachiyomi.util.preference.titleRes
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
|
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
|
||||||
import eu.kanade.tachiyomi.util.system.isTablet
|
import eu.kanade.tachiyomi.util.system.isTablet
|
||||||
import eu.kanade.tachiyomi.widget.preference.ThemesPreference
|
import eu.kanade.tachiyomi.widget.preference.ThemesPreference
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
@ -24,10 +24,8 @@ import android.util.TypedValue
|
|||||||
import android.view.Display
|
import android.view.Display
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.view.ContextThemeWrapper
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
@ -52,29 +50,6 @@ import kotlin.math.roundToInt
|
|||||||
|
|
||||||
private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720
|
private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a toast in this context.
|
|
||||||
*
|
|
||||||
* @param resource the text resource.
|
|
||||||
* @param duration the duration of the toast. Defaults to short.
|
|
||||||
*/
|
|
||||||
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
|
||||||
return toast(getString(resource), duration, block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display a toast in this context.
|
|
||||||
*
|
|
||||||
* @param text the text to display.
|
|
||||||
* @param duration the duration of the toast. Defaults to short.
|
|
||||||
*/
|
|
||||||
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
|
||||||
return Toast.makeText(applicationContext, text.orEmpty(), duration).also {
|
|
||||||
block(it)
|
|
||||||
it.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies a string to clipboard
|
* Copies a string to clipboard
|
||||||
*
|
*
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import com.google.android.material.color.DynamicColors
|
||||||
|
|
||||||
|
val DeviceUtil.isDynamicColorAvailable by lazy {
|
||||||
|
DynamicColors.isDynamicColorAvailable() || (DeviceUtil.isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||||
|
}
|
@ -12,8 +12,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterEhBinding
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
import exh.metadata.MetadataUtil
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit) {
|
||||||
@ -29,7 +29,7 @@ fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
val binding = DescriptionAdapterEhBinding.bind(it)
|
val binding = DescriptionAdapterEhBinding.bind(it)
|
||||||
|
|
||||||
binding.genre.text =
|
binding.genre.text =
|
||||||
meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }
|
meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }
|
||||||
?.let {
|
?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
@ -61,7 +61,7 @@ fun EHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
val ratingFloat = meta.averageRating?.toFloat()
|
val ratingFloat = meta.averageRating?.toFloat()
|
||||||
binding.ratingBar.rating = ratingFloat ?: 0F
|
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
binding.rating.text = (ratingFloat ?: 0F).toString() + " - " + MetadataUtil.getRatingString(context, ratingFloat?.times(2))
|
binding.rating.text = (ratingFloat ?: 0F).toString() + " - " + MetadataUIUtil.getRatingString(context, ratingFloat?.times(2))
|
||||||
|
|
||||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapter8mBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapter8mBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.EightMusesSearchMetadata
|
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EightMusesDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
fun EightMusesDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
||||||
|
@ -10,8 +10,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHbBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterHbBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.HBrowseSearchMetadata
|
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HBrowseDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
fun HBrowseDescription(state: MangaScreenState.Success, openMetadataViewer: () -> Unit) {
|
||||||
|
@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterHiBinding
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
import exh.metadata.MetadataUtil
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.HitomiSearchMetadata
|
import exh.metadata.metadata.HitomiSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -28,7 +28,7 @@ fun HitomiDescription(state: MangaScreenState.Success, openMetadataViewer: () ->
|
|||||||
if (meta == null || meta !is HitomiSearchMetadata) return@AndroidView
|
if (meta == null || meta !is HitomiSearchMetadata) return@AndroidView
|
||||||
val binding = DescriptionAdapterHiBinding.bind(it)
|
val binding = DescriptionAdapterHiBinding.bind(it)
|
||||||
|
|
||||||
binding.genre.text = meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
binding.genre.text = meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
} ?: meta.genre ?: context.getString(R.string.unknown)
|
} ?: meta.genre ?: context.getString(R.string.unknown)
|
||||||
|
@ -12,9 +12,9 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterMdBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterMdBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil.getRatingString
|
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.getRatingString
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
65
app/src/main/java/exh/metadata/MetadataUtil.kt → app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt
Executable file → Normal file
65
app/src/main/java/exh/metadata/MetadataUtil.kt → app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt
Executable file → Normal file
@ -1,72 +1,17 @@
|
|||||||
package exh.metadata
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.FloatRange
|
import androidx.annotation.FloatRange
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.source.R
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import exh.util.SourceTagsUtil
|
import exh.util.SourceTagsUtil
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import kotlin.math.ln
|
|
||||||
import kotlin.math.pow
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
object MetadataUIUtil {
|
||||||
* Metadata utils
|
|
||||||
*/
|
|
||||||
object MetadataUtil {
|
|
||||||
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
|
||||||
val unit = if (si) 1000 else 1024
|
|
||||||
if (bytes < unit) return "$bytes B"
|
|
||||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
|
||||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
|
||||||
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val KB_FACTOR: Long = 1000
|
|
||||||
private const val KIB_FACTOR: Long = 1024
|
|
||||||
private const val MB_FACTOR = 1000 * KB_FACTOR
|
|
||||||
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
|
||||||
private const val GB_FACTOR = 1000 * MB_FACTOR
|
|
||||||
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
|
||||||
|
|
||||||
fun parseHumanReadableByteCount(bytes: String): Double? {
|
|
||||||
val ret = bytes.substringBefore(' ').toDouble()
|
|
||||||
return when (bytes.substringAfter(' ')) {
|
|
||||||
"GB" -> ret * GB_FACTOR
|
|
||||||
"GiB" -> ret * GIB_FACTOR
|
|
||||||
"MB" -> ret * MB_FACTOR
|
|
||||||
"MiB" -> ret * MIB_FACTOR
|
|
||||||
"KB" -> ret * KB_FACTOR
|
|
||||||
"KiB" -> ret * KIB_FACTOR
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val ONGOING_SUFFIX = arrayOf(
|
|
||||||
"[ongoing]",
|
|
||||||
"(ongoing)",
|
|
||||||
"{ongoing}",
|
|
||||||
"<ongoing>",
|
|
||||||
"ongoing",
|
|
||||||
"[incomplete]",
|
|
||||||
"(incomplete)",
|
|
||||||
"{incomplete}",
|
|
||||||
"<incomplete>",
|
|
||||||
"incomplete",
|
|
||||||
"[wip]",
|
|
||||||
"(wip)",
|
|
||||||
"{wip}",
|
|
||||||
"<wip>",
|
|
||||||
"wip",
|
|
||||||
)
|
|
||||||
|
|
||||||
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
|
||||||
|
|
||||||
fun getRatingString(context: Context, @FloatRange(from = 0.0, to = 10.0) rating: Float? = null) = when (rating?.roundToInt()) {
|
fun getRatingString(context: Context, @FloatRange(from = 0.0, to = 10.0) rating: Float? = null) = when (rating?.roundToInt()) {
|
||||||
0 -> R.string.rating0
|
0 -> R.string.rating0
|
||||||
1 -> R.string.rating1
|
1 -> R.string.rating1
|
||||||
@ -103,12 +48,12 @@ object MetadataUtil {
|
|||||||
}?.let { (genreColor, stringId) ->
|
}?.let { (genreColor, stringId) ->
|
||||||
genreColor.color to context.getString(stringId)
|
genreColor.color to context.getString(stringId)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun TextView.bindDrawable(context: Context, @DrawableRes drawable: Int) {
|
fun TextView.bindDrawable(context: Context, @DrawableRes drawable: Int) {
|
||||||
ContextCompat.getDrawable(context, drawable)?.apply {
|
ContextCompat.getDrawable(context, drawable)?.apply {
|
||||||
setTint(context.getResourceColor(R.attr.colorAccent))
|
setTint(context.getResourceColor(R.attr.colorAccent))
|
||||||
setBounds(0, 0, 20.dpToPx, 20.dpToPx)
|
setBounds(0, 0, 20.dpToPx, 20.dpToPx)
|
||||||
setCompoundDrawables(this, null, null, null)
|
setCompoundDrawables(this, null, null, null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -12,8 +12,8 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterNhBinding
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
import exh.metadata.MetadataUtil
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.NHentaiSearchMetadata
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -32,7 +32,7 @@ fun NHentaiDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
binding.genre.text = meta.tags.filter { it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE }.let { tags ->
|
binding.genre.text = meta.tags.filter { it.namespace == NHentaiSearchMetadata.NHENTAI_CATEGORIES_NAMESPACE }.let { tags ->
|
||||||
if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null
|
if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null
|
||||||
}.let { categoriesString ->
|
}.let { categoriesString ->
|
||||||
categoriesString?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
categoriesString?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
} ?: categoriesString ?: context.getString(R.string.unknown)
|
} ?: categoriesString ?: context.getString(R.string.unknown)
|
||||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPeBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPeBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.PervEdenSearchMetadata
|
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ fun PervEdenDescription(state: MangaScreenState.Success, openMetadataViewer: ()
|
|||||||
if (meta == null || meta !is PervEdenSearchMetadata) return@AndroidView
|
if (meta == null || meta !is PervEdenSearchMetadata) return@AndroidView
|
||||||
val binding = DescriptionAdapterPeBinding.bind(it)
|
val binding = DescriptionAdapterPeBinding.bind(it)
|
||||||
|
|
||||||
binding.genre.text = meta.genre?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
binding.genre.text = meta.genre?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
} ?: meta.genre ?: context.getString(R.string.unknown)
|
} ?: meta.genre ?: context.getString(R.string.unknown)
|
||||||
@ -45,7 +44,7 @@ fun PervEdenDescription(state: MangaScreenState.Success, openMetadataViewer: ()
|
|||||||
|
|
||||||
binding.ratingBar.rating = meta.rating ?: 0F
|
binding.ratingBar.rating = meta.rating ?: 0F
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
binding.rating.text = (round((meta.rating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, meta.rating?.times(2))
|
binding.rating.text = (round((meta.rating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, meta.rating?.times(2))
|
||||||
|
|
||||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||||
|
|
||||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPuBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterPuBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.PururinSearchMetadata
|
import exh.metadata.metadata.PururinSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -30,7 +29,7 @@ fun PururinDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
val binding = DescriptionAdapterPuBinding.bind(it)
|
val binding = DescriptionAdapterPuBinding.bind(it)
|
||||||
|
|
||||||
binding.genre.text = meta.tags.find { it.namespace == PururinSearchMetadata.TAG_NAMESPACE_CATEGORY }.let { genre ->
|
binding.genre.text = meta.tags.find { it.namespace == PururinSearchMetadata.TAG_NAMESPACE_CATEGORY }.let { genre ->
|
||||||
genre?.let { MetadataUtil.getGenreAndColour(context, it.name) }?.let {
|
genre?.let { MetadataUIUtil.getGenreAndColour(context, it.name) }?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
} ?: genre?.name ?: context.getString(R.string.unknown)
|
} ?: genre?.name ?: context.getString(R.string.unknown)
|
||||||
@ -47,7 +46,7 @@ fun PururinDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
val ratingFloat = meta.averageRating?.toFloat()
|
val ratingFloat = meta.averageRating?.toFloat()
|
||||||
binding.ratingBar.rating = ratingFloat ?: 0F
|
binding.ratingBar.rating = ratingFloat ?: 0F
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
binding.rating.text = (round((ratingFloat ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, ratingFloat?.times(2))
|
binding.rating.text = (round((ratingFloat ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, ratingFloat?.times(2))
|
||||||
|
|
||||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||||
|
|
||||||
|
@ -11,9 +11,8 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.databinding.DescriptionAdapterTsBinding
|
import eu.kanade.tachiyomi.databinding.DescriptionAdapterTsBinding
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import exh.metadata.MetadataUtil
|
|
||||||
import exh.metadata.bindDrawable
|
|
||||||
import exh.metadata.metadata.TsuminoSearchMetadata
|
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.bindDrawable
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ fun TsuminoDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
if (meta == null || meta !is TsuminoSearchMetadata) return@AndroidView
|
if (meta == null || meta !is TsuminoSearchMetadata) return@AndroidView
|
||||||
val binding = DescriptionAdapterTsBinding.bind(it)
|
val binding = DescriptionAdapterTsBinding.bind(it)
|
||||||
|
|
||||||
binding.genre.text = meta.category?.let { MetadataUtil.getGenreAndColour(context, it) }?.let {
|
binding.genre.text = meta.category?.let { MetadataUIUtil.getGenreAndColour(context, it) }?.let {
|
||||||
binding.genre.setBackgroundColor(it.first)
|
binding.genre.setBackgroundColor(it.first)
|
||||||
it.second
|
it.second
|
||||||
} ?: meta.category ?: context.getString(R.string.unknown)
|
} ?: meta.category ?: context.getString(R.string.unknown)
|
||||||
@ -47,7 +46,7 @@ fun TsuminoDescription(state: MangaScreenState.Success, openMetadataViewer: () -
|
|||||||
|
|
||||||
binding.ratingBar.rating = meta.averageRating ?: 0F
|
binding.ratingBar.rating = meta.averageRating ?: 0F
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
binding.rating.text = (round((meta.averageRating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUtil.getRatingString(context, meta.averageRating?.times(2))
|
binding.rating.text = (round((meta.averageRating ?: 0F) * 100.0) / 100.0).toString() + " - " + MetadataUIUtil.getRatingString(context, meta.averageRating?.times(2))
|
||||||
|
|
||||||
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
binding.moreInfo.bindDrawable(context, R.drawable.ic_info_24dp)
|
||||||
|
|
||||||
|
@ -34,12 +34,12 @@ object SourceTagsUtil {
|
|||||||
}
|
}
|
||||||
if (parsed?.namespace != null) {
|
if (parsed?.namespace != null) {
|
||||||
when (sourceId) {
|
when (sourceId) {
|
||||||
in hitomiSourceIds -> wrapTagHitomi(parsed.namespace, parsed.name.substringBefore('|').trim())
|
in hitomiSourceIds -> wrapTagHitomi(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||||
in nHentaiSourceIds -> wrapTagNHentai(parsed.namespace, parsed.name.substringBefore('|').trim())
|
in nHentaiSourceIds -> wrapTagNHentai(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||||
in mangaDexSourceIds -> parsed.name
|
in mangaDexSourceIds -> parsed.name
|
||||||
PURURIN_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
PURURIN_SOURCE_ID -> parsed.name.substringBefore('|').trim()
|
||||||
TSUMINO_SOURCE_ID -> wrapTagTsumino(parsed.namespace, parsed.name.substringBefore('|').trim())
|
TSUMINO_SOURCE_ID -> wrapTagTsumino(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||||
else -> wrapTag(parsed.namespace, parsed.name.substringBefore('|').trim())
|
else -> wrapTag(parsed.namespace!!, parsed.name.substringBefore('|').trim())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
/*
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package exh.util
|
|
||||||
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
fun String.capitalize(locale: Locale = Locale.getDefault()) =
|
|
||||||
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }
|
|
1
core/.gitignore
vendored
Normal file
1
core/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
50
core/build.gradle.kts
Normal file
50
core/build.gradle.kts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.library")
|
||||||
|
kotlin("android")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "eu.kanade.tachiyomi.core"
|
||||||
|
compileSdk = AndroidConfig.compileSdk
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = AndroidConfig.minSdk
|
||||||
|
targetSdk = AndroidConfig.targetSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":i18n"))
|
||||||
|
|
||||||
|
api(libs.logcat)
|
||||||
|
|
||||||
|
api(libs.rxjava)
|
||||||
|
|
||||||
|
api(libs.okhttp.core)
|
||||||
|
api(libs.okhttp.logging)
|
||||||
|
api(libs.okhttp.dnsoverhttps)
|
||||||
|
api(libs.okio)
|
||||||
|
|
||||||
|
api(kotlinx.coroutines.core)
|
||||||
|
api(kotlinx.serialization.json)
|
||||||
|
|
||||||
|
api(libs.injekt.core)
|
||||||
|
|
||||||
|
api(libs.preferencektx)
|
||||||
|
|
||||||
|
implementation(androidx.corektx)
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
implementation(sylibs.xlog)
|
||||||
|
// SY <--
|
||||||
|
}
|
2
core/src/main/AndroidManifest.xml
Normal file
2
core/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest />
|
@ -1,22 +1,22 @@
|
|||||||
package eu.kanade.tachiyomi.network
|
package eu.kanade.tachiyomi.network
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import androidx.preference.PreferenceManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.i18n.BuildConfig
|
||||||
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
|
import eu.kanade.tachiyomi.network.interceptor.CloudflareInterceptor
|
||||||
import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor
|
import eu.kanade.tachiyomi.network.interceptor.Http103Interceptor
|
||||||
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
import eu.kanade.tachiyomi.network.interceptor.UserAgentInterceptor
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
/* SY --> */
|
/* SY --> */
|
||||||
open /* SY <-- */ class NetworkHelper(context: Context) {
|
open /* SY <-- */ class NetworkHelper(context: Context) {
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
// TODO: Abstract preferences similar to 1.x
|
||||||
|
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
private val cacheDir = File(context.cacheDir, "network_cache")
|
private val cacheDir = File(context.cacheDir, "network_cache")
|
||||||
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
private val cacheSize = 5L * 1024 * 1024 // 5 MiB
|
||||||
@ -46,7 +46,7 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
|
|||||||
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
builder.addNetworkInterceptor(httpLoggingInterceptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
when (preferences.dohProvider()) {
|
when (preferences.getInt("doh_provider", -1)) {
|
||||||
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
PREF_DOH_CLOUDFLARE -> builder.dohCloudflare()
|
||||||
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
PREF_DOH_GOOGLE -> builder.dohGoogle()
|
||||||
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
PREF_DOH_ADGUARD -> builder.dohAdGuard()
|
||||||
@ -74,6 +74,6 @@ open /* SY <-- */ class NetworkHelper(context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val defaultUserAgent by lazy {
|
val defaultUserAgent by lazy {
|
||||||
preferences.defaultUserAgent().get()
|
preferences.getString("default_user_agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0")!!
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,7 +10,7 @@ import java.util.concurrent.TimeUnit.MINUTES
|
|||||||
private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).build()
|
private val DEFAULT_CACHE_CONTROL = CacheControl.Builder().maxAge(10, MINUTES).build()
|
||||||
private val DEFAULT_HEADERS = Headers.Builder().build()
|
private val DEFAULT_HEADERS = Headers.Builder().build()
|
||||||
private val DEFAULT_BODY: RequestBody = FormBody.Builder().build()
|
private val DEFAULT_BODY: RequestBody = FormBody.Builder().build()
|
||||||
internal val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
val CACHE_CONTROL_NO_STORE = CacheControl.Builder().noStore().build()
|
||||||
|
|
||||||
fun GET(
|
fun GET(
|
||||||
url: String,
|
url: String,
|
@ -5,7 +5,7 @@ import android.content.Context
|
|||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.core.R
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
|
||||||
import eu.kanade.tachiyomi.util.system.isOutdated
|
import eu.kanade.tachiyomi.util.system.isOutdated
|
@ -5,7 +5,7 @@ import android.os.Build
|
|||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.core.R
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
@ -5,6 +5,7 @@ import kotlinx.coroutines.CancellationException
|
|||||||
import kotlinx.coroutines.CoroutineStart
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.InternalCoroutinesApi
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import rx.Emitter
|
import rx.Emitter
|
||||||
@ -20,6 +21,7 @@ import kotlin.coroutines.resumeWithException
|
|||||||
|
|
||||||
suspend fun <T> Observable<T>.awaitSingle(): T = single().awaitOne()
|
suspend fun <T> Observable<T>.awaitSingle(): T = single().awaitOne()
|
||||||
|
|
||||||
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutine { cont ->
|
private suspend fun <T> Observable<T>.awaitOne(): T = suspendCancellableCoroutine { cont ->
|
||||||
cont.unsubscribeOnCancellation(
|
cont.unsubscribeOnCancellation(
|
||||||
subscribe(
|
subscribe(
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.util.system
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.google.android.material.color.DynamicColors
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
|
||||||
object DeviceUtil {
|
object DeviceUtil {
|
||||||
@ -31,10 +30,6 @@ object DeviceUtil {
|
|||||||
Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
Build.MANUFACTURER.equals("samsung", ignoreCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isDynamicColorAvailable by lazy {
|
|
||||||
DynamicColors.isDynamicColorAvailable() || (isSamsung && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
|
||||||
}
|
|
||||||
|
|
||||||
val invalidDefaultBrowsers = listOf("android", "com.huawei.android.internal.app")
|
val invalidDefaultBrowsers = listOf("android", "com.huawei.android.internal.app")
|
||||||
|
|
||||||
@SuppressLint("PrivateApi")
|
@SuppressLint("PrivateApi")
|
@ -0,0 +1,28 @@
|
|||||||
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a toast in this context.
|
||||||
|
*
|
||||||
|
* @param resource the text resource.
|
||||||
|
* @param duration the duration of the toast. Defaults to short.
|
||||||
|
*/
|
||||||
|
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||||
|
return toast(getString(resource), duration, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a toast in this context.
|
||||||
|
*
|
||||||
|
* @param text the text to display.
|
||||||
|
* @param duration the duration of the toast. Defaults to short.
|
||||||
|
*/
|
||||||
|
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT, block: (Toast) -> Unit = {}): Toast {
|
||||||
|
return Toast.makeText(applicationContext, text.orEmpty(), duration).also {
|
||||||
|
block(it)
|
||||||
|
it.show()
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,7 @@ package exh.log
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.core.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys
|
|
||||||
|
|
||||||
enum class EHLogLevel(@StringRes val nameRes: Int, @StringRes val description: Int) {
|
enum class EHLogLevel(@StringRes val nameRes: Int, @StringRes val description: Int) {
|
||||||
MINIMAL(R.string.log_minimal, R.string.log_minimal_desc),
|
MINIMAL(R.string.log_minimal, R.string.log_minimal_desc),
|
||||||
@ -19,7 +18,7 @@ enum class EHLogLevel(@StringRes val nameRes: Int, @StringRes val description: I
|
|||||||
|
|
||||||
fun init(context: Context) {
|
fun init(context: Context) {
|
||||||
curLogLevel = PreferenceManager.getDefaultSharedPreferences(context)
|
curLogLevel = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getInt(PreferenceKeys.eh_logLevel, 0)
|
.getInt("eh_log_level", 0) // todo
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldLog(requiredLogLevel: EHLogLevel): Boolean {
|
fun shouldLog(requiredLogLevel: EHLogLevel): Boolean {
|
@ -1,5 +1,7 @@
|
|||||||
package exh.util
|
package exh.util
|
||||||
|
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
fun Collection<String>.trimAll() = map { it.trim() }
|
fun Collection<String>.trimAll() = map { it.trim() }
|
||||||
fun Collection<String>.dropBlank() = filter { it.isNotBlank() }
|
fun Collection<String>.dropBlank() = filter { it.isNotBlank() }
|
||||||
fun Collection<String>.dropEmpty() = filter { it.isNotEmpty() }
|
fun Collection<String>.dropEmpty() = filter { it.isNotEmpty() }
|
||||||
@ -13,3 +15,6 @@ fun String.removeArticles(): String {
|
|||||||
fun String.trimOrNull() = trim().nullIfBlank()
|
fun String.trimOrNull() = trim().nullIfBlank()
|
||||||
|
|
||||||
fun String.nullIfBlank(): String? = ifBlank { null }
|
fun String.nullIfBlank(): String? = ifBlank { null }
|
||||||
|
|
||||||
|
fun String.capitalize(locale: Locale = Locale.getDefault()) =
|
||||||
|
replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }
|
@ -40,3 +40,5 @@ dependencyResolutionManagement {
|
|||||||
rootProject.name = "TachiyomiSY"
|
rootProject.name = "TachiyomiSY"
|
||||||
include(":app")
|
include(":app")
|
||||||
include(":i18n")
|
include(":i18n")
|
||||||
|
include(":source-api")
|
||||||
|
include(":core")
|
||||||
|
1
source-api/.gitignore
vendored
Normal file
1
source-api/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
44
source-api/build.gradle.kts
Normal file
44
source-api/build.gradle.kts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
plugins {
|
||||||
|
id("com.android.library")
|
||||||
|
kotlin("android")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "eu.kanade.tachiyomi.source"
|
||||||
|
compileSdk = AndroidConfig.compileSdk
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = AndroidConfig.minSdk
|
||||||
|
targetSdk = AndroidConfig.targetSdk
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation(project(":core"))
|
||||||
|
|
||||||
|
api(kotlinx.serialization.json)
|
||||||
|
|
||||||
|
api(libs.rxjava)
|
||||||
|
|
||||||
|
api(libs.preferencektx)
|
||||||
|
|
||||||
|
api(libs.jsoup)
|
||||||
|
|
||||||
|
implementation(androidx.corektx)
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
implementation(project(":i18n"))
|
||||||
|
implementation(kotlinx.reflect)
|
||||||
|
// SY <--
|
||||||
|
}
|
2
source-api/src/main/AndroidManifest.xml
Normal file
2
source-api/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest />
|
@ -1,16 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.source
|
package eu.kanade.tachiyomi.source
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import eu.kanade.domain.source.model.SourceData
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
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.util.lang.awaitSingle
|
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A basic interface for creating a source. It could be an online source, a local source, etc...
|
* A basic interface for creating a source. It could be an online source, a local source, etc...
|
||||||
@ -88,53 +82,3 @@ interface Source {
|
|||||||
return fetchPageList(chapter).awaitSingle()
|
return fetchPageList(chapter).awaitSingle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Source.icon(): Drawable? = Injekt.get<ExtensionManager>().getAppIconForSource(this)
|
|
||||||
|
|
||||||
fun Source.getPreferenceKey(): String = "source_$id"
|
|
||||||
|
|
||||||
fun Source.toSourceData(): SourceData = SourceData(id = id, lang = lang, name = name)
|
|
||||||
|
|
||||||
fun Source.getNameForMangaInfo(mergeSources: List<Source>?): String {
|
|
||||||
val preferences = Injekt.get<PreferencesHelper>()
|
|
||||||
val enabledLanguages = preferences.enabledLanguages().get()
|
|
||||||
.filterNot { it in listOf("all", "other") }
|
|
||||||
val hasOneActiveLanguages = enabledLanguages.size == 1
|
|
||||||
val isInEnabledLanguages = lang in enabledLanguages
|
|
||||||
return when {
|
|
||||||
// SY -->
|
|
||||||
!mergeSources.isNullOrEmpty() -> getMergedSourcesString(
|
|
||||||
mergeSources,
|
|
||||||
enabledLanguages,
|
|
||||||
hasOneActiveLanguages,
|
|
||||||
)
|
|
||||||
// SY <--
|
|
||||||
// For edge cases where user disables a source they got manga of in their library.
|
|
||||||
hasOneActiveLanguages && !isInEnabledLanguages -> toString()
|
|
||||||
// Hide the language tag when only one language is used.
|
|
||||||
hasOneActiveLanguages && isInEnabledLanguages -> name
|
|
||||||
else -> toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SY -->
|
|
||||||
private fun getMergedSourcesString(
|
|
||||||
mergeSources: List<Source>,
|
|
||||||
enabledLangs: List<String>,
|
|
||||||
onlyName: Boolean,
|
|
||||||
): String {
|
|
||||||
return if (onlyName) {
|
|
||||||
mergeSources.joinToString { source ->
|
|
||||||
if (source.lang !in enabledLangs) {
|
|
||||||
source.toString()
|
|
||||||
} else {
|
|
||||||
source.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mergeSources.joinToString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
fun Source.isLocalOrStub(): Boolean = id == LocalSource.ID || this is SourceManager.StubSource
|
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.source.model
|
package eu.kanade.tachiyomi.source.model
|
||||||
|
|
||||||
import data.Chapters
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
interface SChapter : Serializable {
|
interface SChapter : Serializable {
|
||||||
@ -23,14 +22,6 @@ interface SChapter : Serializable {
|
|||||||
scanlator = other.scanlator
|
scanlator = other.scanlator
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyFrom(other: Chapters) {
|
|
||||||
name = other.name
|
|
||||||
url = other.url
|
|
||||||
date_upload = other.date_upload
|
|
||||||
chapter_number = other.chapter_number
|
|
||||||
scanlator = other.scanlator
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(): SChapter {
|
fun create(): SChapter {
|
||||||
return SChapterImpl()
|
return SChapterImpl()
|
@ -1,11 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.source.model
|
package eu.kanade.tachiyomi.source.model
|
||||||
|
|
||||||
import data.Mangas
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
interface SManga : Serializable {
|
interface SManga : Serializable {
|
||||||
@ -35,28 +29,17 @@ interface SManga : Serializable {
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val originalTitle: String
|
val originalTitle: String
|
||||||
get() = (this as? MangaImpl)?.ogTitle ?: title
|
|
||||||
val originalAuthor: String?
|
val originalAuthor: String?
|
||||||
get() = (this as? MangaImpl)?.ogAuthor ?: author
|
|
||||||
val originalArtist: String?
|
val originalArtist: String?
|
||||||
get() = (this as? MangaImpl)?.ogArtist ?: artist
|
|
||||||
val originalDescription: String?
|
val originalDescription: String?
|
||||||
get() = (this as? MangaImpl)?.ogDesc ?: description
|
|
||||||
val originalGenre: String?
|
val originalGenre: String?
|
||||||
get() = (this as? MangaImpl)?.ogGenre ?: genre
|
|
||||||
val originalStatus: Int
|
val originalStatus: Int
|
||||||
get() = (this as? MangaImpl)?.ogStatus ?: status
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
fun copyFrom(other: SManga) {
|
fun copyFrom(other: SManga) {
|
||||||
// EXH -->
|
// EXH -->
|
||||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
if (other.title.isNotBlank() && originalTitle != other.title) {
|
||||||
val oldTitle = originalTitle
|
|
||||||
title = other.originalTitle
|
title = other.originalTitle
|
||||||
val source = (this as? Manga)?.source
|
|
||||||
if (source != null) {
|
|
||||||
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.originalTitle, source)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
@ -87,45 +70,6 @@ interface SManga : Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyFrom(other: Mangas) {
|
|
||||||
// EXH -->
|
|
||||||
if (other.title.isNotBlank() && originalTitle != other.title) {
|
|
||||||
val oldTitle = originalTitle
|
|
||||||
title = other.title
|
|
||||||
val source = (this as? Manga)?.source
|
|
||||||
if (source != null) {
|
|
||||||
Injekt.get<DownloadManager>().renameMangaDir(oldTitle, other.title, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// EXH <--
|
|
||||||
|
|
||||||
if (other.author != null) {
|
|
||||||
author = other.author
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.artist != null) {
|
|
||||||
artist = other.artist
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.description != null) {
|
|
||||||
description = other.description
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.genre != null) {
|
|
||||||
genre = other.genre.joinToString(separator = ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.thumbnail_url != null) {
|
|
||||||
thumbnail_url = other.thumbnail_url
|
|
||||||
}
|
|
||||||
|
|
||||||
status = other.status.toInt()
|
|
||||||
|
|
||||||
if (!initialized) {
|
|
||||||
initialized = other.initialized
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun copy() = create().also {
|
fun copy() = create().also {
|
||||||
it.url = url
|
it.url = url
|
||||||
// SY -->
|
// SY -->
|
@ -21,4 +21,19 @@ class SMangaImpl : SManga {
|
|||||||
override var thumbnail_url: String? = null
|
override var thumbnail_url: String? = null
|
||||||
|
|
||||||
override var initialized: Boolean = false
|
override var initialized: Boolean = false
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
override val originalTitle: String
|
||||||
|
get() = title
|
||||||
|
override val originalAuthor: String?
|
||||||
|
get() = author
|
||||||
|
override val originalArtist: String?
|
||||||
|
get() = artist
|
||||||
|
override val originalDescription: String?
|
||||||
|
get() = description
|
||||||
|
override val originalGenre: String?
|
||||||
|
get() = genre
|
||||||
|
override val originalStatus: Int
|
||||||
|
get() = status
|
||||||
|
// SY <--
|
||||||
}
|
}
|
@ -1,10 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
package eu.kanade.tachiyomi.source.online
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.md.utils.FollowStatus
|
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
|
||||||
interface FollowsSource : CatalogueSource {
|
interface FollowsSource : CatalogueSource {
|
||||||
@ -16,14 +14,4 @@ interface FollowsSource : CatalogueSource {
|
|||||||
* @param SManga all smanga found for user
|
* @param SManga all smanga found for user
|
||||||
*/
|
*/
|
||||||
suspend fun fetchAllFollows(): List<Pair<SManga, RaisedSearchMetadata>>
|
suspend fun fetchAllFollows(): List<Pair<SManga, RaisedSearchMetadata>>
|
||||||
|
|
||||||
/**
|
|
||||||
* updates the follow status for a manga
|
|
||||||
*/
|
|
||||||
suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a MdList Track of the manga
|
|
||||||
*/
|
|
||||||
suspend fun fetchTrackingInfo(url: String): Track
|
|
||||||
}
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
package eu.kanade.tachiyomi.source.online
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.network.AndroidCookieJar
|
import eu.kanade.tachiyomi.network.AndroidCookieJar
|
||||||
import eu.kanade.tachiyomi.network.CACHE_CONTROL_NO_STORE
|
import eu.kanade.tachiyomi.network.CACHE_CONTROL_NO_STORE
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
@ -15,7 +14,6 @@ import eu.kanade.tachiyomi.source.model.Page
|
|||||||
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 exh.log.maybeInjectEHLogger
|
import exh.log.maybeInjectEHLogger
|
||||||
import exh.patch.injectPatches
|
|
||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -43,14 +41,14 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
override val client: OkHttpClient
|
override val client: OkHttpClient
|
||||||
get() = delegate?.networkHttpClient ?: network.client
|
get() = delegate?.networkHttpClient ?: network.client
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.injectPatches { id }
|
//.injectPatches { id } todo
|
||||||
.maybeInjectEHLogger()
|
.maybeInjectEHLogger()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override val cloudflareClient: OkHttpClient
|
override val cloudflareClient: OkHttpClient
|
||||||
get() = delegate?.networkCloudflareClient ?: network.cloudflareClient
|
get() = delegate?.networkCloudflareClient ?: network.cloudflareClient
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
.injectPatches { id }
|
//.injectPatches { id } todo
|
||||||
.maybeInjectEHLogger()
|
.maybeInjectEHLogger()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
@ -411,7 +409,7 @@ abstract class HttpSource : CatalogueSource {
|
|||||||
|
|
||||||
// EXH -->
|
// EXH -->
|
||||||
private var delegate: DelegatedHttpSource? = null
|
private var delegate: DelegatedHttpSource? = null
|
||||||
get() = if (Injekt.get<PreferencesHelper>().delegateSources().get()) {
|
get() = if (Injekt.get<NetworkHelper>().preferences.getBoolean("eh_delegate_sources", true)) { // todo
|
||||||
field
|
field
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
@ -1,14 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.source.online
|
package eu.kanade.tachiyomi.source.online
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import eu.kanade.domain.manga.interactor.GetFlatMetadataById
|
|
||||||
import eu.kanade.domain.manga.interactor.GetManga
|
|
||||||
import eu.kanade.domain.manga.interactor.InsertFlatMetadata
|
|
||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaScreenState
|
|
||||||
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
import eu.kanade.tachiyomi.util.lang.awaitSingle
|
||||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||||
|
import exh.metadata.metadata.base.FlatMetadata
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
@ -20,7 +16,16 @@ import kotlin.reflect.KClass
|
|||||||
* LEWD!
|
* LEWD!
|
||||||
*/
|
*/
|
||||||
interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
||||||
val getManga: GetManga get() = Injekt.get()
|
interface GetMangaId {
|
||||||
|
suspend fun awaitId(url: String, sourceId: Long): Long?
|
||||||
|
}
|
||||||
|
interface InsertFlatMetadata {
|
||||||
|
suspend fun await(metadata: RaisedSearchMetadata)
|
||||||
|
}
|
||||||
|
interface GetFlatMetadataById {
|
||||||
|
suspend fun await(id: Long): FlatMetadata?
|
||||||
|
}
|
||||||
|
val getMangaId: GetMangaId get() = Injekt.get()
|
||||||
val insertFlatMetadata: InsertFlatMetadata get() = Injekt.get()
|
val insertFlatMetadata: InsertFlatMetadata get() = Injekt.get()
|
||||||
val getFlatMetadataById: GetFlatMetadataById get() = Injekt.get()
|
val getFlatMetadataById: GetFlatMetadataById get() = Injekt.get()
|
||||||
|
|
||||||
@ -111,8 +116,5 @@ interface MetadataSource<M : RaisedSearchMetadata, I> : CatalogueSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
suspend fun SManga.id() = getMangaId.awaitId(url, id)
|
||||||
fun DescriptionComposable(state: MangaScreenState.Success, openMetadataViewer: () -> Unit, search: (String) -> Unit)
|
|
||||||
|
|
||||||
suspend fun SManga.id() = getManga.await(url, id)?.id
|
|
||||||
}
|
}
|
@ -12,6 +12,7 @@ import org.jsoup.nodes.Element
|
|||||||
/**
|
/**
|
||||||
* A simple implementation for sources from a website using Jsoup, an HTML parser.
|
* A simple implementation for sources from a website using Jsoup, an HTML parser.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("unused")
|
||||||
abstract class ParsedHttpSource : HttpSource() {
|
abstract class ParsedHttpSource : HttpSource() {
|
||||||
|
|
||||||
/**
|
/**
|
@ -1,7 +1,7 @@
|
|||||||
package exh.md.utils
|
package exh.md.utils
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.source.R
|
||||||
|
|
||||||
enum class MangaDexRelation(@StringRes val resId: Int, val mdString: String?) {
|
enum class MangaDexRelation(@StringRes val resId: Int, val mdString: String?) {
|
||||||
SIMILAR(R.string.relation_similar, null),
|
SIMILAR(R.string.relation_similar, null),
|
60
source-api/src/main/java/exh/metadata/MetadataUtil.kt
Normal file
60
source-api/src/main/java/exh/metadata/MetadataUtil.kt
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package exh.metadata
|
||||||
|
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
import kotlin.math.ln
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata utils
|
||||||
|
*/
|
||||||
|
object MetadataUtil {
|
||||||
|
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
||||||
|
val unit = if (si) 1000 else 1024
|
||||||
|
if (bytes < unit) return "$bytes B"
|
||||||
|
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||||
|
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
||||||
|
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val KB_FACTOR: Long = 1000
|
||||||
|
private const val KIB_FACTOR: Long = 1024
|
||||||
|
private const val MB_FACTOR = 1000 * KB_FACTOR
|
||||||
|
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
||||||
|
private const val GB_FACTOR = 1000 * MB_FACTOR
|
||||||
|
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
||||||
|
|
||||||
|
fun parseHumanReadableByteCount(bytes: String): Double? {
|
||||||
|
val ret = bytes.substringBefore(' ').toDouble()
|
||||||
|
return when (bytes.substringAfter(' ')) {
|
||||||
|
"GB" -> ret * GB_FACTOR
|
||||||
|
"GiB" -> ret * GIB_FACTOR
|
||||||
|
"MB" -> ret * MB_FACTOR
|
||||||
|
"MiB" -> ret * MIB_FACTOR
|
||||||
|
"KB" -> ret * KB_FACTOR
|
||||||
|
"KiB" -> ret * KIB_FACTOR
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ONGOING_SUFFIX = arrayOf(
|
||||||
|
"[ongoing]",
|
||||||
|
"(ongoing)",
|
||||||
|
"{ongoing}",
|
||||||
|
"<ongoing>",
|
||||||
|
"ongoing",
|
||||||
|
"[incomplete]",
|
||||||
|
"(incomplete)",
|
||||||
|
"{incomplete}",
|
||||||
|
"<incomplete>",
|
||||||
|
"incomplete",
|
||||||
|
"[wip]",
|
||||||
|
"(wip)",
|
||||||
|
"{wip}",
|
||||||
|
"<wip>",
|
||||||
|
"wip",
|
||||||
|
)
|
||||||
|
|
||||||
|
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,8 @@ package exh.metadata.metadata
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.source.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.model.copy
|
import eu.kanade.tachiyomi.source.model.copy
|
||||||
import exh.metadata.MetadataUtil
|
import exh.metadata.MetadataUtil
|
||||||
@ -53,7 +53,7 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
// No title bug?
|
// No title bug?
|
||||||
val title = altTitle
|
val title = altTitle
|
||||||
?.takeIf { Injekt.get<PreferencesHelper>().useJapaneseTitle().get() }
|
?.takeIf { Injekt.get<NetworkHelper>().preferences.getBoolean("use_jp_title", false) } // todo
|
||||||
?: title
|
?: title
|
||||||
|
|
||||||
// Set artist (if we can find one)
|
// Set artist (if we can find one)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user