Compare commits
1 Commits
v7.2.1
...
feature/dy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d8820bcab |
@@ -82,7 +82,7 @@ afterEvaluate {
|
||||
}
|
||||
dependencies {
|
||||
//noinspection GradleDependency
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:7ed8c9f787') {
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:f923acc5a7') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.util.ext.almostEquals
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import javax.inject.Inject
|
||||
@@ -57,7 +58,7 @@ class AlternativesUseCase @Inject constructor(
|
||||
}
|
||||
|
||||
private suspend fun getSources(ref: MangaSource): List<MangaSource> {
|
||||
val result = ArrayList<MangaSource>(MangaSource.entries.size - 2)
|
||||
val result = ArrayList<MangaSource>(MangaParserSource.entries.size - 2)
|
||||
result.addAll(sourcesRepository.getEnabledSources())
|
||||
result.sortByDescending { it.priority(ref) }
|
||||
result.addAll(sourcesRepository.getDisabledSources().sortedByDescending { it.priority(ref) })
|
||||
@@ -78,8 +79,10 @@ class AlternativesUseCase @Inject constructor(
|
||||
|
||||
private fun MangaSource.priority(ref: MangaSource): Int {
|
||||
var res = 0
|
||||
if (locale == ref.locale) res += 2
|
||||
if (contentType == ref.contentType) res++
|
||||
if (this is MangaParserSource && ref is MangaParserSource) {
|
||||
if (locale == ref.locale) res += 2
|
||||
if (contentType == ref.contentType) res++
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import coil.request.ImageRequest
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
||||
import org.koitharu.kotatsu.core.ui.image.ChipIconTarget
|
||||
import org.koitharu.kotatsu.core.ui.image.CoverSizeResolver
|
||||
@@ -63,7 +64,7 @@ fun alternativeAD(
|
||||
}
|
||||
binding.progressView.setPercent(item.progress, ListModelDiffCallback.PAYLOAD_PROGRESS_CHANGED in payloads)
|
||||
binding.chipSource.also { chip ->
|
||||
chip.text = item.manga.source.title
|
||||
chip.text = item.manga.source.getTitle(chip.context)
|
||||
ImageRequest.Builder(context)
|
||||
.data(item.manga.source.faviconUri())
|
||||
.lifecycle(lifecycleOwner)
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.parser.MangaIntent
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
@@ -95,9 +96,9 @@ class AlternativesActivity : BaseActivity<ActivityAlternativesBinding>(),
|
||||
getString(
|
||||
R.string.migrate_confirmation,
|
||||
viewModel.manga.title,
|
||||
viewModel.manga.source.title,
|
||||
viewModel.manga.source.getTitle(this),
|
||||
target.title,
|
||||
target.source.title,
|
||||
target.source.getTitle(this),
|
||||
),
|
||||
)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
|
||||
@@ -12,13 +12,14 @@ import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import okhttp3.internal.userAgent
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.util.ext.configureForParser
|
||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.toUriOrNull
|
||||
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
@@ -42,10 +43,9 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
|
||||
}
|
||||
val userAgent = intent?.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE)?.let { source ->
|
||||
val repository = mangaRepositoryFactory.create(source) as? RemoteMangaRepository
|
||||
repository?.headers?.get(CommonHeaders.USER_AGENT)
|
||||
}
|
||||
val mangaSource = MangaSource(intent?.getStringExtra(EXTRA_SOURCE))
|
||||
val repository = mangaRepositoryFactory.create(mangaSource) as? RemoteMangaRepository
|
||||
repository?.headers?.get(CommonHeaders.USER_AGENT)
|
||||
viewBinding.webView.configureForParser(userAgent)
|
||||
CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true)
|
||||
viewBinding.webView.webViewClient = BrowserClient(this)
|
||||
@@ -147,7 +147,7 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
return Intent(context, BrowserActivity::class.java)
|
||||
.setData(Uri.parse(url))
|
||||
.putExtra(EXTRA_TITLE, title)
|
||||
.putExtra(EXTRA_SOURCE, source)
|
||||
.putExtra(EXTRA_SOURCE, source?.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,9 @@ import coil.request.ErrorResult
|
||||
import coil.request.ImageRequest
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
class CaptchaNotifier(
|
||||
@@ -46,7 +47,7 @@ class CaptchaNotifier(
|
||||
.setGroup(GROUP_CAPTCHA)
|
||||
.setAutoCancel(true)
|
||||
.setVisibility(
|
||||
if (exception.source?.contentType == ContentType.HENTAI) {
|
||||
if (exception.source?.isNsfw() == true) {
|
||||
NotificationCompat.VISIBILITY_SECRET
|
||||
} else {
|
||||
NotificationCompat.VISIBILITY_PUBLIC
|
||||
@@ -55,7 +56,7 @@ class CaptchaNotifier(
|
||||
.setContentText(
|
||||
context.getString(
|
||||
R.string.captcha_required_summary,
|
||||
exception.source?.title ?: context.getString(R.string.app_name),
|
||||
exception.source?.getTitle(context) ?: context.getString(R.string.app_name),
|
||||
),
|
||||
)
|
||||
.setContentIntent(PendingIntentCompat.getActivity(context, 0, intent, 0, false))
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.content.Context
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
class Migration16To17(context: Context) : Migration(16, 17) {
|
||||
|
||||
@@ -15,11 +15,8 @@ class Migration16To17(context: Context) : Migration(16, 17) {
|
||||
db.execSQL("CREATE INDEX `index_sources_sort_key` ON `sources` (`sort_key`)")
|
||||
val hiddenSources = prefs.getStringSet("sources_hidden", null).orEmpty()
|
||||
val order = prefs.getString("sources_order_2", null)?.split('|').orEmpty()
|
||||
val sources = MangaSource.entries
|
||||
val sources = MangaParserSource.entries
|
||||
for (source in sources) {
|
||||
if (source == MangaSource.LOCAL) {
|
||||
continue
|
||||
}
|
||||
val name = source.name
|
||||
val isHidden = name in hiddenSources
|
||||
var sortKey = order.indexOf(name)
|
||||
|
||||
@@ -11,7 +11,6 @@ import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.util.formatSimple
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
@@ -109,7 +108,7 @@ fun Manga.getPreferredBranch(history: MangaHistory?): String? {
|
||||
}
|
||||
|
||||
val Manga.isLocal: Boolean
|
||||
get() = source == MangaSource.LOCAL
|
||||
get() = source == LocalMangaSource
|
||||
|
||||
val Manga.appUrl: Uri
|
||||
get() = Uri.parse("https://kotatsu.app/manga").buildUpon()
|
||||
|
||||
@@ -7,24 +7,41 @@ import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.text.style.SuperscriptSpan
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.inSpans
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayName
|
||||
import org.koitharu.kotatsu.core.util.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.core.util.ext.toLocale
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
fun MangaSource(name: String): MangaSource {
|
||||
MangaSource.entries.forEach {
|
||||
if (it.name == name) return it
|
||||
}
|
||||
return MangaSource.UNKNOWN
|
||||
data object LocalMangaSource : MangaSource {
|
||||
override val name = "LOCAL"
|
||||
}
|
||||
|
||||
fun MangaSource.isNsfw() = contentType == ContentType.HENTAI
|
||||
data object UnknownMangaSource : MangaSource {
|
||||
override val name = "UNKNOWN"
|
||||
}
|
||||
|
||||
fun MangaSource(name: String?): MangaSource {
|
||||
when (name) {
|
||||
null,
|
||||
UnknownMangaSource.name -> UnknownMangaSource
|
||||
|
||||
LocalMangaSource.name -> LocalMangaSource
|
||||
}
|
||||
MangaParserSource.entries.forEach {
|
||||
if (it.name == name) return it
|
||||
}
|
||||
return UnknownMangaSource
|
||||
}
|
||||
|
||||
fun MangaSource.isNsfw() = when (this) {
|
||||
is MangaParserSource -> contentType == ContentType.HENTAI
|
||||
else -> false
|
||||
}
|
||||
|
||||
@get:StringRes
|
||||
val ContentType.titleResId
|
||||
@@ -35,23 +52,23 @@ val ContentType.titleResId
|
||||
ContentType.OTHER -> R.string.content_type_other
|
||||
}
|
||||
|
||||
fun MangaSource.getSummary(context: Context): String {
|
||||
val type = context.getString(contentType.titleResId)
|
||||
val locale = locale.toLocale().getDisplayName(context)
|
||||
return context.getString(R.string.source_summary_pattern, type, locale)
|
||||
}
|
||||
|
||||
fun MangaSource.getTitle(context: Context): CharSequence = if (isNsfw()) {
|
||||
buildSpannedString {
|
||||
append(title)
|
||||
append(' ')
|
||||
appendNsfwLabel(context)
|
||||
fun MangaSource.getSummary(context: Context): String? = when (this) {
|
||||
is MangaParserSource -> {
|
||||
val type = context.getString(contentType.titleResId)
|
||||
val locale = locale.toLocale().getDisplayName(context)
|
||||
context.getString(R.string.source_summary_pattern, type, locale)
|
||||
}
|
||||
} else {
|
||||
title
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun SpannableStringBuilder.appendNsfwLabel(context: Context) = inSpans(
|
||||
fun MangaSource.getTitle(context: Context): String = when (this) {
|
||||
is MangaParserSource -> title
|
||||
LocalMangaSource -> context.getString(R.string.local_storage)
|
||||
else -> context.getString(R.string.unknown)
|
||||
}
|
||||
|
||||
fun SpannableStringBuilder.appendNsfwLabel(context: Context) = inSpans(
|
||||
ForegroundColorSpan(context.getThemeColor(materialR.attr.colorError, Color.RED)),
|
||||
RelativeSizeSpan(0.74f),
|
||||
SuperscriptSpan(),
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.koitharu.kotatsu.core.model.parcelable
|
||||
|
||||
import android.os.Parcel
|
||||
import kotlinx.parcelize.Parceler
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
class MangaSourceParceler : Parceler<MangaSource> {
|
||||
|
||||
override fun create(parcel: Parcel): MangaSource = MangaSource(parcel.readString())
|
||||
|
||||
override fun MangaSource.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(name)
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,8 @@ import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parceler
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@Parcelize
|
||||
data class ParcelableChapter(
|
||||
@@ -25,8 +24,8 @@ data class ParcelableChapter(
|
||||
scanlator = parcel.readString(),
|
||||
uploadDate = parcel.readLong(),
|
||||
branch = parcel.readString(),
|
||||
source = parcel.readSerializableCompat() ?: MangaSource.UNKNOWN,
|
||||
)
|
||||
source = MangaSource(parcel.readString()),
|
||||
),
|
||||
)
|
||||
|
||||
override fun ParcelableChapter.write(parcel: Parcel, flags: Int) = with(chapter) {
|
||||
@@ -38,7 +37,7 @@ data class ParcelableChapter(
|
||||
parcel.writeString(scanlator)
|
||||
parcel.writeLong(uploadDate)
|
||||
parcel.writeString(branch)
|
||||
parcel.writeSerializable(source)
|
||||
parcel.writeString(source.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Parcelable
|
||||
import androidx.core.os.ParcelCompat
|
||||
import kotlinx.parcelize.Parceler
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.util.ext.readParcelableCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
@@ -30,7 +31,7 @@ data class ParcelableManga(
|
||||
parcel.writeParcelable(ParcelableMangaTags(tags), flags)
|
||||
parcel.writeSerializable(state)
|
||||
parcel.writeString(author)
|
||||
parcel.writeSerializable(source)
|
||||
parcel.writeString(source.name)
|
||||
}
|
||||
|
||||
override fun create(parcel: Parcel) = ParcelableManga(
|
||||
@@ -49,8 +50,8 @@ data class ParcelableManga(
|
||||
state = parcel.readSerializableCompat(),
|
||||
author = parcel.readString(),
|
||||
chapters = null,
|
||||
source = requireNotNull(parcel.readSerializableCompat()),
|
||||
)
|
||||
source = MangaSource(parcel.readString()),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parceler
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.TypeParceler
|
||||
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
|
||||
object MangaPageParceler : Parceler<MangaPage> {
|
||||
@@ -13,14 +13,14 @@ object MangaPageParceler : Parceler<MangaPage> {
|
||||
id = parcel.readLong(),
|
||||
url = requireNotNull(parcel.readString()),
|
||||
preview = parcel.readString(),
|
||||
source = requireNotNull(parcel.readSerializableCompat()),
|
||||
source = MangaSource(parcel.readString()),
|
||||
)
|
||||
|
||||
override fun MangaPage.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeLong(id)
|
||||
parcel.writeString(url)
|
||||
parcel.writeString(preview)
|
||||
parcel.writeSerializable(source)
|
||||
parcel.writeString(source.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,20 @@ import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parceler
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.TypeParceler
|
||||
import org.koitharu.kotatsu.core.util.ext.readSerializableCompat
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
|
||||
object MangaTagParceler : Parceler<MangaTag> {
|
||||
override fun create(parcel: Parcel) = MangaTag(
|
||||
title = requireNotNull(parcel.readString()),
|
||||
key = requireNotNull(parcel.readString()),
|
||||
source = requireNotNull(parcel.readSerializableCompat()),
|
||||
source = MangaSource(parcel.readString()),
|
||||
)
|
||||
|
||||
override fun MangaTag.write(parcel: Parcel, flags: Int) {
|
||||
parcel.writeString(title)
|
||||
parcel.writeString(key)
|
||||
parcel.writeSerializable(source)
|
||||
parcel.writeString(source.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import okhttp3.internal.publicsuffix.PublicSuffixDatabase
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import java.util.EnumMap
|
||||
import javax.inject.Inject
|
||||
@@ -26,8 +27,8 @@ class MirrorSwitchInterceptor @Inject constructor(
|
||||
private val settings: AppSettings,
|
||||
) : Interceptor {
|
||||
|
||||
private val locks = EnumMap<MangaSource, Any>(MangaSource::class.java)
|
||||
private val blacklist = EnumMap<MangaSource, MutableSet<String>>(MangaSource::class.java)
|
||||
private val locks = EnumMap<MangaParserSource, Any>(MangaParserSource::class.java)
|
||||
private val blacklist = EnumMap<MangaParserSource, MutableSet<String>>(MangaParserSource::class.java)
|
||||
|
||||
val isEnabled: Boolean
|
||||
get() = settings.isMirrorSwitchingAvailable
|
||||
@@ -145,15 +146,15 @@ class MirrorSwitchInterceptor @Inject constructor(
|
||||
return source().readByteArray().toResponseBody(contentType())
|
||||
}
|
||||
|
||||
private fun obtainLock(source: MangaSource): Any = locks.getOrPut(source) {
|
||||
private fun obtainLock(source: MangaParserSource): Any = locks.getOrPut(source) {
|
||||
Any()
|
||||
}
|
||||
|
||||
private fun isBlacklisted(source: MangaSource, domain: String): Boolean {
|
||||
private fun isBlacklisted(source: MangaParserSource, domain: String): Boolean {
|
||||
return blacklist[source]?.contains(domain) == true
|
||||
}
|
||||
|
||||
private fun addToBlacklist(source: MangaSource, domain: String) {
|
||||
private fun addToBlacklist(source: MangaParserSource, domain: String) {
|
||||
blacklist.getOrPut(source) {
|
||||
ArraySet(2)
|
||||
}.add(domain)
|
||||
|
||||
@@ -21,6 +21,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.TABLE_HISTORY
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.parser.favicon.faviconUri
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
@@ -173,9 +174,10 @@ class AppShortcutManager @Inject constructor(
|
||||
onSuccess = { IconCompat.createWithAdaptiveBitmap(it) },
|
||||
onFailure = { IconCompat.createWithResource(context, R.drawable.ic_shortcut_default) },
|
||||
)
|
||||
val title = source.getTitle(context)
|
||||
ShortcutInfoCompat.Builder(context, source.name)
|
||||
.setShortLabel(source.title)
|
||||
.setLongLabel(source.title)
|
||||
.setShortLabel(title)
|
||||
.setLongLabel(title)
|
||||
.setIcon(icon)
|
||||
.setLongLived(true)
|
||||
.setIntent(MangaListActivity.newIntent(context, source))
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import java.util.EnumSet
|
||||
@@ -16,7 +16,7 @@ import java.util.EnumSet
|
||||
/**
|
||||
* This parser is just for parser development, it should not be used in releases
|
||||
*/
|
||||
class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.DUMMY) {
|
||||
class DummyParser(context: MangaLoaderContext) : MangaParser(context, MangaParserSource.DUMMY) {
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain
|
||||
get() = ConfigKey.Domain("localhost")
|
||||
|
||||
@@ -1,38 +1,52 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import java.util.EnumSet
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* This parser is just for parser development, it should not be used in releases
|
||||
*/
|
||||
class EmptyParser(context: MangaLoaderContext) : MangaParser(context, MangaSource.DUMMY) {
|
||||
class EmptyMangaRepository(override val source: MangaSource) : MangaRepository {
|
||||
|
||||
override val configKeyDomain: ConfigKey.Domain
|
||||
get() = ConfigKey.Domain("localhost")
|
||||
|
||||
override val availableSortOrders: Set<SortOrder>
|
||||
override val sortOrders: Set<SortOrder>
|
||||
get() = EnumSet.allOf(SortOrder::class.java)
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = stub(manga)
|
||||
override val states: Set<MangaState>
|
||||
get() = emptySet()
|
||||
override val contentRatings: Set<ContentRating>
|
||||
get() = emptySet()
|
||||
override var defaultSortOrder: SortOrder
|
||||
get() = SortOrder.NEWEST
|
||||
set(value) = Unit
|
||||
override val isMultipleTagsSupported: Boolean
|
||||
get() = false
|
||||
override val isTagsExclusionSupported: Boolean
|
||||
get() = false
|
||||
override val isSearchSupported: Boolean
|
||||
get() = false
|
||||
|
||||
override suspend fun getList(offset: Int, filter: MangaListFilter?): List<Manga> = stub(null)
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = stub(manga)
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> = stub(null)
|
||||
|
||||
override suspend fun getAvailableTags(): Set<MangaTag> = stub(null)
|
||||
override suspend fun getPageUrl(page: MangaPage): String = stub(null)
|
||||
|
||||
override suspend fun getRelatedManga(seed: Manga): List<Manga> = stub(seed)
|
||||
override suspend fun getTags(): Set<MangaTag> = stub(null)
|
||||
|
||||
override suspend fun getLocales(): Set<Locale> = stub(null)
|
||||
|
||||
override suspend fun getRelated(seed: Manga): List<Manga> = stub(seed)
|
||||
|
||||
private fun stub(manga: Manga?): Nothing {
|
||||
throw UnsupportedSourceException("This manga source is not supported", manga)
|
||||
@@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.entity.toEntities
|
||||
import org.koitharu.kotatsu.core.db.entity.toEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.toManga
|
||||
import org.koitharu.kotatsu.core.db.entity.toMangaTags
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
||||
import org.koitharu.kotatsu.core.util.ext.toFileOrNull
|
||||
@@ -101,7 +102,7 @@ class MangaDataRepository @Inject constructor(
|
||||
|
||||
suspend fun cleanupLocalManga() {
|
||||
val dao = db.getMangaDao()
|
||||
val broken = dao.findAllBySource(MangaSource.LOCAL.name)
|
||||
val broken = dao.findAllBySource(LocalMangaSource.name)
|
||||
.filter { x -> x.manga.url.toUri().toFileOrNull()?.exists() == false }
|
||||
if (broken.isNotEmpty()) {
|
||||
dao.delete(broken.map { it.manga })
|
||||
|
||||
@@ -4,10 +4,11 @@ import android.net.Uri
|
||||
import coil.request.CachePolicy
|
||||
import dagger.Reusable
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.UnknownMangaSource
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
@@ -36,7 +37,7 @@ class MangaLinkResolver @Inject constructor(
|
||||
require(uri.pathSegments.singleOrNull() == "manga") { "Invalid url" }
|
||||
val sourceName = requireNotNull(uri.getQueryParameter("source")) { "Source is not specified" }
|
||||
val source = MangaSource(sourceName)
|
||||
require(source != MangaSource.UNKNOWN) { "Manga source $sourceName is not supported" }
|
||||
require(source != UnknownMangaSource) { "Manga source $sourceName is not supported" }
|
||||
val repo = repositoryFactory.create(source)
|
||||
return repo.findExact(
|
||||
url = uri.getQueryParameter("url"),
|
||||
@@ -108,7 +109,7 @@ class MangaLinkResolver @Inject constructor(
|
||||
url = url,
|
||||
publicUrl = "",
|
||||
rating = 0.0f,
|
||||
isNsfw = source.contentType == ContentType.HENTAI,
|
||||
isNsfw = source.isNsfw(),
|
||||
coverUrl = "",
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
|
||||
@@ -2,12 +2,11 @@ package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
fun MangaParser(source: MangaSource, loaderContext: MangaLoaderContext): MangaParser {
|
||||
fun MangaParser(source: MangaParserSource, loaderContext: MangaLoaderContext): MangaParser {
|
||||
return when (source) {
|
||||
MangaSource.UNKNOWN -> EmptyParser(loaderContext)
|
||||
MangaSource.DUMMY -> DummyParser(loaderContext)
|
||||
MangaParserSource.DUMMY -> DummyParser(loaderContext)
|
||||
else -> loaderContext.newParserInstance(source)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.parser
|
||||
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.collection.ArrayMap
|
||||
import org.koitharu.kotatsu.core.cache.MemoryContentCache
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.UnknownMangaSource
|
||||
import org.koitharu.kotatsu.core.network.MirrorSwitchInterceptor
|
||||
import org.koitharu.kotatsu.local.data.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
@@ -10,12 +13,12 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.EnumMap
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
@@ -61,24 +64,35 @@ interface MangaRepository {
|
||||
private val mirrorSwitchInterceptor: MirrorSwitchInterceptor,
|
||||
) {
|
||||
|
||||
private val cache = EnumMap<MangaSource, WeakReference<RemoteMangaRepository>>(MangaSource::class.java)
|
||||
private val cache = ArrayMap<MangaSource, WeakReference<MangaRepository>>()
|
||||
|
||||
@AnyThread
|
||||
fun create(source: MangaSource): MangaRepository {
|
||||
if (source == MangaSource.LOCAL) {
|
||||
return localMangaRepository
|
||||
when (source) {
|
||||
LocalMangaSource -> return localMangaRepository
|
||||
UnknownMangaSource -> return EmptyMangaRepository(source)
|
||||
}
|
||||
cache[source]?.get()?.let { return it }
|
||||
return synchronized(cache) {
|
||||
cache[source]?.get()?.let { return it }
|
||||
val repository = RemoteMangaRepository(
|
||||
parser = MangaParser(source, loaderContext),
|
||||
cache = contentCache,
|
||||
mirrorSwitchInterceptor = mirrorSwitchInterceptor,
|
||||
)
|
||||
cache[source] = WeakReference(repository)
|
||||
repository
|
||||
val repository = createRepository(source)
|
||||
if (repository != null) {
|
||||
cache[source] = WeakReference(repository)
|
||||
repository
|
||||
} else {
|
||||
EmptyMangaRepository(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRepository(source: MangaSource): MangaRepository? = when (source) {
|
||||
is MangaParserSource -> RemoteMangaRepository(
|
||||
parser = MangaParser(source, loaderContext),
|
||||
cache = contentCache,
|
||||
mirrorSwitchInterceptor = mirrorSwitchInterceptor,
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
@@ -46,7 +46,7 @@ class RemoteMangaRepository(
|
||||
private val relatedMangaMutex = MultiMutex<Long>()
|
||||
private val pagesMutex = MultiMutex<Long>()
|
||||
|
||||
override val source: MangaSource
|
||||
override val source: MangaParserSource
|
||||
get() = parser.source
|
||||
|
||||
override val sortOrders: Set<SortOrder>
|
||||
|
||||
@@ -46,7 +46,7 @@ class FaviconFetcher(
|
||||
) : Fetcher {
|
||||
|
||||
private val diskCacheKey
|
||||
get() = options.diskCacheKey ?: "${mangaSource.name}[${mangaSource.ordinal}]x${options.size.toCacheKey()}"
|
||||
get() = options.diskCacheKey ?: "${mangaSource.name}x${options.size.toCacheKey()}"
|
||||
|
||||
private val fileSystem
|
||||
get() = checkNotNull(diskCache.value).fileSystem
|
||||
|
||||
@@ -5,7 +5,9 @@ import android.content.Intent
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.EntryPointAccessors
|
||||
import org.koitharu.kotatsu.core.cache.MemoryContentCache
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.findById
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableChapter
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
@@ -62,7 +64,7 @@ class MangaPrefetchService : CoroutineIntentService() {
|
||||
|
||||
private suspend fun prefetchLast() {
|
||||
val last = historyRepository.getLastOrNull() ?: return
|
||||
if (last.source == MangaSource.LOCAL) return
|
||||
if (last.isLocal) return
|
||||
val repo = mangaRepositoryFactory.create(last.source)
|
||||
val details = runCatchingCancellable { repo.getDetails(last) }.getOrNull() ?: return
|
||||
val chapters = details.chapters
|
||||
@@ -110,7 +112,7 @@ class MangaPrefetchService : CoroutineIntentService() {
|
||||
}
|
||||
|
||||
private fun isPrefetchAvailable(context: Context, source: MangaSource?): Boolean {
|
||||
if (source == MangaSource.LOCAL || context.isPowerSaveMode()) {
|
||||
if (source == LocalMangaSource || context.isPowerSaveMode()) {
|
||||
return false
|
||||
}
|
||||
val entryPoint = EntryPointAccessors.fromApplication(
|
||||
|
||||
@@ -43,6 +43,9 @@ import kotlinx.coroutines.flow.map
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.UnknownMangaSource
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.iconResId
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.model.titleResId
|
||||
@@ -94,7 +97,6 @@ import org.koitharu.kotatsu.list.ui.model.MangaItemModel
|
||||
import org.koitharu.kotatsu.list.ui.size.StaticItemSizeResolver
|
||||
import org.koitharu.kotatsu.local.ui.info.LocalInfoDialog
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.util.ellipsize
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
@@ -463,10 +465,10 @@ class DetailsActivity :
|
||||
imageViewState.isVisible = false
|
||||
}
|
||||
|
||||
if (manga.source == MangaSource.LOCAL || manga.source == MangaSource.UNKNOWN) {
|
||||
if (manga.source == LocalMangaSource || manga.source == UnknownMangaSource) {
|
||||
infoLayout.chipSource.isVisible = false
|
||||
} else {
|
||||
infoLayout.chipSource.text = manga.source.title
|
||||
infoLayout.chipSource.text = manga.source.getTitle(this@DetailsActivity)
|
||||
infoLayout.chipSource.isVisible = true
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,12 @@ import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.alternatives.ui.AlternativesActivity
|
||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.os.AppShortcutManager
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
import org.koitharu.kotatsu.download.ui.dialog.DownloadOption
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
|
||||
import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity
|
||||
import org.koitharu.kotatsu.stats.ui.sheet.MangaStatsSheet
|
||||
@@ -38,10 +39,10 @@ class DetailsMenuProvider(
|
||||
|
||||
override fun onPrepareMenu(menu: Menu) {
|
||||
val manga = viewModel.manga.value
|
||||
menu.findItem(R.id.action_save).isVisible = manga?.source != null && manga.source != MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_delete).isVisible = manga?.source == MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_browser).isVisible = manga?.source != MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_alternatives).isVisible = manga?.source != MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_save).isVisible = manga?.source != null && manga.source != LocalMangaSource
|
||||
menu.findItem(R.id.action_delete).isVisible = manga?.source == LocalMangaSource
|
||||
menu.findItem(R.id.action_browser).isVisible = manga?.source != LocalMangaSource
|
||||
menu.findItem(R.id.action_alternatives).isVisible = manga?.source != LocalMangaSource
|
||||
menu.findItem(R.id.action_shortcut).isVisible = ShortcutManagerCompat.isRequestPinShortcutSupported(activity)
|
||||
menu.findItem(R.id.action_scrobbling).isVisible = viewModel.isScrobblingAvailable
|
||||
menu.findItem(R.id.action_online).isVisible = viewModel.remoteManga.value != null
|
||||
@@ -53,7 +54,7 @@ class DetailsMenuProvider(
|
||||
R.id.action_share -> {
|
||||
viewModel.manga.value?.let {
|
||||
val shareHelper = ShareHelper(activity)
|
||||
if (it.source == MangaSource.LOCAL) {
|
||||
if (it.isLocal) {
|
||||
shareHelper.shareCbz(listOf(it.url.toUri().toFile()))
|
||||
} else {
|
||||
shareHelper.shareMangaLink(it)
|
||||
|
||||
@@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
@@ -40,7 +41,6 @@ import org.koitharu.kotatsu.details.ui.withVolumeHeaders
|
||||
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.local.ui.LocalChaptersRemoveService
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderNavigationCallback
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
@@ -218,7 +218,7 @@ class ChaptersFragment :
|
||||
var canSave = true
|
||||
var canDelete = true
|
||||
items.forEach { (_, x) ->
|
||||
val isLocal = x.isDownloaded || x.chapter.source == MangaSource.LOCAL
|
||||
val isLocal = x.isDownloaded || x.chapter.source == LocalMangaSource
|
||||
if (isLocal) canSave = false else canDelete = false
|
||||
}
|
||||
menu.findItem(R.id.action_save).isVisible = canSave
|
||||
|
||||
@@ -21,13 +21,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.util.ext.getDrawableOrThrow
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.download.domain.DownloadState
|
||||
import org.koitharu.kotatsu.download.ui.list.DownloadsActivity
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.format
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
@@ -231,7 +231,7 @@ class DownloadNotificationFactory @AssistedInject constructor(
|
||||
if (manga != null) {
|
||||
DetailsActivity.newIntent(context, manga)
|
||||
} else {
|
||||
MangaListActivity.newIntent(context, MangaSource.LOCAL)
|
||||
MangaListActivity.newIntent(context, LocalMangaSource)
|
||||
},
|
||||
PendingIntent.FLAG_CANCEL_CURRENT,
|
||||
false,
|
||||
|
||||
@@ -43,6 +43,7 @@ import okio.sink
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.TooManyRequestExceptions
|
||||
import org.koitharu.kotatsu.core.model.ids
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.network.MangaHttpClient
|
||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||
@@ -177,7 +178,7 @@ class DownloadWorker @AssistedInject constructor(
|
||||
checkNotNull(destination) { applicationContext.getString(R.string.cannot_find_available_storage) }
|
||||
var output: LocalMangaOutput? = null
|
||||
try {
|
||||
if (manga.source == MangaSource.LOCAL) {
|
||||
if (manga.isLocal) {
|
||||
manga = localMangaRepository.getRemoteManga(manga)
|
||||
?: error("Cannot obtain remote manga instance")
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleHandle
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import java.util.Collections
|
||||
@@ -34,15 +35,13 @@ class MangaSourcesRepository @Inject constructor(
|
||||
private val dao: MangaSourcesDao
|
||||
get() = db.getSourcesDao()
|
||||
|
||||
private val remoteSources = EnumSet.allOf(MangaSource::class.java).apply {
|
||||
remove(MangaSource.LOCAL)
|
||||
remove(MangaSource.UNKNOWN)
|
||||
private val remoteSources = EnumSet.allOf(MangaParserSource::class.java).apply {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
remove(MangaSource.DUMMY)
|
||||
remove(MangaParserSource.DUMMY)
|
||||
}
|
||||
}
|
||||
|
||||
val allMangaSources: Set<MangaSource>
|
||||
val allMangaSources: Set<MangaParserSource>
|
||||
get() = Collections.unmodifiableSet(remoteSources)
|
||||
|
||||
suspend fun getEnabledSources(): List<MangaSource> {
|
||||
@@ -70,7 +69,7 @@ class MangaSourcesRepository @Inject constructor(
|
||||
query: String?,
|
||||
locale: String?,
|
||||
sortOrder: SourcesSortOrder?,
|
||||
): List<MangaSource> {
|
||||
): List<MangaParserSource> {
|
||||
assimilateNewSources()
|
||||
val entities = dao.findAll().toMutableList()
|
||||
if (isDisabledOnly) {
|
||||
@@ -236,7 +235,7 @@ class MangaSourcesRepository @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getNewSources(): MutableSet<MangaSource> {
|
||||
private suspend fun getNewSources(): MutableSet<out MangaSource> {
|
||||
val entities = dao.findAll()
|
||||
val result = EnumSet.copyOf(remoteSources)
|
||||
for (e in entities) {
|
||||
@@ -248,8 +247,8 @@ class MangaSourcesRepository @Inject constructor(
|
||||
private fun List<MangaSourceEntity>.toSources(
|
||||
skipNsfwSources: Boolean,
|
||||
sortOrder: SourcesSortOrder?,
|
||||
): MutableList<MangaSource> {
|
||||
val result = ArrayList<MangaSource>(size)
|
||||
): MutableList<MangaParserSource> {
|
||||
val result = ArrayList<MangaParserSource>(size)
|
||||
for (entity in this) {
|
||||
val source = entity.source.toMangaSourceOrNull() ?: continue
|
||||
if (skipNsfwSources && source.isNsfw()) {
|
||||
@@ -273,5 +272,5 @@ class MangaSourcesRepository @Inject constructor(
|
||||
sourcesSortOrder
|
||||
}
|
||||
|
||||
private fun String.toMangaSourceOrNull(): MangaSource? = MangaSource.entries.find { it.name == this }
|
||||
private fun String.toMangaSourceOrNull(): MangaParserSource? = MangaParserSource.entries.find { it.name == this }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.explore.domain
|
||||
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.almostEquals
|
||||
@@ -7,7 +8,6 @@ import org.koitharu.kotatsu.core.util.ext.asArrayList
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
@@ -45,7 +45,7 @@ class ExploreRepository @Inject constructor(
|
||||
|
||||
suspend fun findRandomManga(source: MangaSource, tagsLimit: Int): Manga {
|
||||
val tagsBlacklist = TagsBlacklist(settings.suggestionsTagsBlacklist, 0.4f)
|
||||
val skipNsfw = settings.isSuggestionsExcludeNsfw && source.contentType != ContentType.HENTAI
|
||||
val skipNsfw = settings.isSuggestionsExcludeNsfw && !source.isNsfw()
|
||||
val tags = historyRepository.getPopularTags(tagsLimit).mapNotNull {
|
||||
if (it in tagsBlacklist) null else it.title
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.ui.AllBookmarksActivity
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.ui.dialog.TwoButtonsAlertDialog
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
@@ -40,7 +41,7 @@ import org.koitharu.kotatsu.explore.ui.model.MangaSourceItem
|
||||
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
||||
import org.koitharu.kotatsu.list.ui.model.ListHeader
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
@@ -123,7 +124,7 @@ class ExploreFragment :
|
||||
|
||||
override fun onClick(v: View) {
|
||||
val intent = when (v.id) {
|
||||
R.id.button_local -> MangaListActivity.newIntent(v.context, MangaSource.LOCAL)
|
||||
R.id.button_local -> MangaListActivity.newIntent(v.context, LocalMangaSource)
|
||||
R.id.button_bookmarks -> AllBookmarksActivity.newIntent(v.context)
|
||||
R.id.button_more -> SuggestionsActivity.newIntent(v.context)
|
||||
R.id.button_downloads -> DownloadsActivity.newIntent(v.context)
|
||||
@@ -173,7 +174,7 @@ class ExploreFragment :
|
||||
|
||||
override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean {
|
||||
val selectedSources = controller.peekCheckedIds().mapNotNullToSet { id ->
|
||||
MangaSource.entries.getOrNull(id.toInt())
|
||||
MangaParserSource.entries.getOrNull(id.toInt()) // TODO
|
||||
}
|
||||
if (selectedSources.isEmpty()) {
|
||||
return false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.explore.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.core.util.ext.longHashCode
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@@ -8,8 +9,7 @@ data class MangaSourceItem(
|
||||
val isGrid: Boolean,
|
||||
) : ListModel {
|
||||
|
||||
val id: Long
|
||||
get() = source.ordinal.toLong()
|
||||
val id: Long = source.name.longHashCode()
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is MangaSourceItem && other.source == source
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package org.koitharu.kotatsu.favourites.domain.model
|
||||
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.find
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
|
||||
data class Cover(
|
||||
val url: String,
|
||||
val source: String,
|
||||
) {
|
||||
val mangaSource: MangaSource?
|
||||
get() = if (source.isEmpty()) null else MangaSource.entries.find(source)
|
||||
val mangaSource by lazy { MangaSource(source) }
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.util.ext.sortedByOrdinal
|
||||
import org.koitharu.kotatsu.core.util.ext.withArgs
|
||||
import org.koitharu.kotatsu.databinding.FragmentListBinding
|
||||
import org.koitharu.kotatsu.list.domain.ListSortOrder
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickListener {
|
||||
@@ -57,9 +57,7 @@ class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickLis
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
menu.findItem(R.id.action_save)?.isVisible = selectedItems.none {
|
||||
it.source == MangaSource.LOCAL
|
||||
}
|
||||
menu.findItem(R.id.action_save)?.isVisible = selectedItems.none { it.isLocal }
|
||||
return super.onPrepareActionMode(controller, mode, menu)
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
import org.koitharu.kotatsu.list.ui.model.toErrorFooter
|
||||
import org.koitharu.kotatsu.parsers.model.ContentRating
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
@@ -451,7 +452,7 @@ class FilterCoordinator @Inject constructor(
|
||||
}
|
||||
|
||||
private fun mergeTags(primary: Set<MangaTag>, secondary: Set<MangaTag>): Set<MangaTag> {
|
||||
val result = TreeSet(TagTitleComparator(repository.source.locale))
|
||||
val result = TreeSet(TagTitleComparator((repository.source as? MangaParserSource)?.locale))
|
||||
result.addAll(secondary)
|
||||
result.addAll(primary)
|
||||
return result
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.os.NetworkManageIntent
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.RecyclerScrollKeeper
|
||||
@@ -17,7 +18,6 @@ import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.databinding.FragmentListBinding
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.list.ui.size.DynamicItemSizeResolver
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@AndroidEntryPoint
|
||||
class HistoryListFragment : MangaListFragment() {
|
||||
@@ -44,9 +44,7 @@ class HistoryListFragment : MangaListFragment() {
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean {
|
||||
menu.findItem(R.id.action_save)?.isVisible = selectedItems.none {
|
||||
it.source == MangaSource.LOCAL
|
||||
}
|
||||
menu.findItem(R.id.action_save)?.isVisible = selectedItems.none { it.isLocal }
|
||||
return super.onPrepareActionMode(controller, mode, menu)
|
||||
}
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.ui.util.PopupMenuMediator
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayIcon
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.getThemeColor
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
@@ -120,7 +120,7 @@ class ImageActivity : BaseActivity<ActivityImageBinding>(), ImageRequest.Listene
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.lifecycle(this)
|
||||
.listener(this)
|
||||
.source(intent.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE))
|
||||
.source(MangaSource(intent.getStringExtra(EXTRA_SOURCE)))
|
||||
.target(SsivTarget(viewBinding.ssiv))
|
||||
.enqueueWith(coil)
|
||||
}
|
||||
@@ -180,7 +180,7 @@ class ImageActivity : BaseActivity<ActivityImageBinding>(), ImageRequest.Listene
|
||||
fun newIntent(context: Context, url: String, source: MangaSource?): Intent {
|
||||
return Intent(context, ImageActivity::class.java)
|
||||
.setData(Uri.parse(url))
|
||||
.putExtra(EXTRA_SOURCE, source)
|
||||
.putExtra(EXTRA_SOURCE, source?.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
@@ -29,7 +30,6 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
@@ -49,7 +49,7 @@ class LocalMangaRepository @Inject constructor(
|
||||
private val settings: AppSettings,
|
||||
) : MangaRepository {
|
||||
|
||||
override val source = MangaSource.LOCAL
|
||||
override val source = LocalMangaSource
|
||||
private val locks = MultiMutex<Long>()
|
||||
private val localMappingCache = LocalMangaMappingCache()
|
||||
|
||||
@@ -100,7 +100,7 @@ class LocalMangaRepository @Inject constructor(
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = when {
|
||||
manga.source != MangaSource.LOCAL -> requireNotNull(findSavedManga(manga)?.manga) {
|
||||
!manga.isLocal -> requireNotNull(findSavedManga(manga)?.manga) {
|
||||
"Manga is not local or saved"
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import androidx.annotation.WorkerThread
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
@@ -58,7 +59,7 @@ class MangaIndex(source: String?) {
|
||||
}
|
||||
|
||||
fun getMangaInfo(): Manga? = if (json.length() == 0) null else runCatching {
|
||||
val source = MangaSource.valueOf(json.getString("source"))
|
||||
val source = MangaSource(json.getString("source"))
|
||||
Manga(
|
||||
id = json.getLong("id"),
|
||||
title = json.getString("title"),
|
||||
|
||||
@@ -4,6 +4,7 @@ import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.util.AlphanumComparator
|
||||
import org.koitharu.kotatsu.core.util.ext.children
|
||||
import org.koitharu.kotatsu.core.util.ext.creationTime
|
||||
@@ -18,7 +19,6 @@ import org.koitharu.kotatsu.local.domain.model.LocalManga
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.toCamelCase
|
||||
import java.io.File
|
||||
import java.util.TreeMap
|
||||
@@ -47,7 +47,7 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
|
||||
index?.getCoverEntry() ?: findFirstImageEntry().orEmpty(),
|
||||
)
|
||||
val manga = info?.copy2(
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
url = mangaUri,
|
||||
coverUrl = cover,
|
||||
largeCoverUrl = cover,
|
||||
@@ -59,14 +59,14 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
|
||||
// old downloads
|
||||
chapterFiles.values.elementAtOrNull(i)
|
||||
} ?: return@mapIndexedNotNull null
|
||||
c.copy(url = file.toUri().toString(), source = MangaSource.LOCAL)
|
||||
c.copy(url = file.toUri().toString(), source = LocalMangaSource)
|
||||
},
|
||||
) ?: Manga(
|
||||
id = root.absolutePath.longHashCode(),
|
||||
title = root.name.toHumanReadable(),
|
||||
url = mangaUri,
|
||||
publicUrl = mangaUri,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
coverUrl = findFirstImageEntry().orEmpty(),
|
||||
chapters = chapterFiles.values.mapIndexed { i, f ->
|
||||
MangaChapter(
|
||||
@@ -74,7 +74,7 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
|
||||
name = f.nameWithoutExtension.toHumanReadable(),
|
||||
number = 0f,
|
||||
volume = 0,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
uploadDate = f.creationTime,
|
||||
url = f.toUri().toString(),
|
||||
scanlator = null,
|
||||
@@ -106,7 +106,7 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
|
||||
.toListSorted(compareBy(AlphanumComparator()) { x -> x.name })
|
||||
.map {
|
||||
val pageUri = it.toUri().toString()
|
||||
MangaPage(pageUri.longHashCode(), pageUri, null, MangaSource.LOCAL)
|
||||
MangaPage(pageUri.longHashCode(), pageUri, null, LocalMangaSource)
|
||||
}
|
||||
} else {
|
||||
ZipFile(file).use { zip ->
|
||||
@@ -121,7 +121,7 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
|
||||
id = pageUri.longHashCode(),
|
||||
url = pageUri,
|
||||
preview = null,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.util.AlphanumComparator
|
||||
import org.koitharu.kotatsu.core.util.ext.longHashCode
|
||||
import org.koitharu.kotatsu.core.util.ext.readText
|
||||
@@ -17,7 +18,6 @@ import org.koitharu.kotatsu.local.domain.model.LocalManga
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.toCamelCase
|
||||
import java.io.File
|
||||
import java.util.Enumeration
|
||||
@@ -47,12 +47,12 @@ class LocalMangaZipInput(root: File) : LocalMangaInput(root) {
|
||||
entryName = index.getCoverEntry() ?: findFirstImageEntry(zip.entries())?.name.orEmpty(),
|
||||
)
|
||||
return@use info.copy2(
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
url = fileUri,
|
||||
coverUrl = cover,
|
||||
largeCoverUrl = cover,
|
||||
chapters = info.chapters?.map { c ->
|
||||
c.copy(url = fileUri, source = MangaSource.LOCAL)
|
||||
c.copy(url = fileUri, source = LocalMangaSource)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -70,7 +70,7 @@ class LocalMangaZipInput(root: File) : LocalMangaInput(root) {
|
||||
title = title,
|
||||
url = fileUri,
|
||||
publicUrl = fileUri,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
coverUrl = zipUri(root, findFirstImageEntry(zip.entries())?.name.orEmpty()),
|
||||
chapters = chapters.sortedWith(AlphanumComparator())
|
||||
.mapIndexed { i, s ->
|
||||
@@ -79,7 +79,7 @@ class LocalMangaZipInput(root: File) : LocalMangaInput(root) {
|
||||
name = s.ifEmpty { title },
|
||||
number = 0f,
|
||||
volume = 0,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
uploadDate = 0L,
|
||||
url = uriBuilder.fragment(s).build().toString(),
|
||||
scanlator = null,
|
||||
@@ -135,7 +135,7 @@ class LocalMangaZipInput(root: File) : LocalMangaInput(root) {
|
||||
id = entryUri.longHashCode(),
|
||||
url = entryUri,
|
||||
preview = null,
|
||||
source = MangaSource.LOCAL,
|
||||
source = LocalMangaSource,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,15 @@ import androidx.core.net.toFile
|
||||
import androidx.core.net.toUri
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
class LocalMangaUtil(
|
||||
private val manga: Manga,
|
||||
) {
|
||||
|
||||
init {
|
||||
require(manga.source == MangaSource.LOCAL) {
|
||||
"Expected LOCAL source but ${manga.source} found"
|
||||
}
|
||||
require(manga.isLocal) { "Expected LOCAL source but ${manga.source} found" }
|
||||
}
|
||||
|
||||
suspend fun deleteChapters(ids: Set<Long>) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.widgets.TipView
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
@@ -26,7 +27,6 @@ import org.koitharu.kotatsu.filter.ui.FilterOwner
|
||||
import org.koitharu.kotatsu.filter.ui.MangaFilter
|
||||
import org.koitharu.kotatsu.filter.ui.sheet.FilterSheetFragment
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
|
||||
import org.koitharu.kotatsu.settings.storage.RequestStorageManagerPermissionContract
|
||||
import org.koitharu.kotatsu.settings.storage.directories.MangaDirectoriesActivity
|
||||
@@ -47,9 +47,9 @@ class LocalListFragment : MangaListFragment(), FilterOwner {
|
||||
|
||||
init {
|
||||
withArgs(1) {
|
||||
putSerializable(
|
||||
putString(
|
||||
RemoteListFragment.ARG_SOURCE,
|
||||
MangaSource.LOCAL,
|
||||
LocalMangaSource.name,
|
||||
) // required by FilterCoordinator
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.os.NetworkState
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import javax.inject.Inject
|
||||
|
||||
class ReadingResumeEnabledUseCase @Inject constructor(
|
||||
@@ -24,7 +24,7 @@ class ReadingResumeEnabledUseCase @Inject constructor(
|
||||
flowOf(false)
|
||||
} else {
|
||||
combine(networkState, historyRepository.observeLast()) { isOnline, last ->
|
||||
last != null && (isOnline || last.source == MangaSource.LOCAL)
|
||||
last != null && (isOnline || last.isLocal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import org.koitharu.kotatsu.core.util.ext.toLocale
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.filter.ui.model.FilterProperty
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import java.util.EnumSet
|
||||
import java.util.Locale
|
||||
@@ -103,7 +103,7 @@ class WelcomeViewModel @Inject constructor(
|
||||
private suspend fun commit() {
|
||||
val languages = locales.value.selectedItems.mapToSet { it.language }
|
||||
val types = types.value.selectedItems
|
||||
val enabledSources = allSources.filterTo(EnumSet.noneOf(MangaSource::class.java)) { x ->
|
||||
val enabledSources = allSources.filterTo(EnumSet.noneOf(MangaParserSource::class.java)) { x ->
|
||||
x.contentType in types && x.locale in languages
|
||||
}
|
||||
repository.setSourcesEnabledExclusive(enabledSources)
|
||||
|
||||
@@ -2,10 +2,13 @@ package org.koitharu.kotatsu.reader.ui.pager
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.TypeParceler
|
||||
import org.koitharu.kotatsu.core.model.parcelable.MangaSourceParceler
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@Parcelize
|
||||
@TypeParceler<MangaSource, MangaSourceParceler>
|
||||
data class ReaderPage(
|
||||
val id: Long,
|
||||
val url: String,
|
||||
|
||||
@@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.distinctUntilChangedBy
|
||||
import kotlinx.coroutines.flow.drop
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.util.MenuInvalidator
|
||||
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
|
||||
@@ -75,7 +76,12 @@ class RemoteListFragment : MangaListFragment(), FilterOwner {
|
||||
override fun onSecondaryErrorActionClick(error: Throwable) {
|
||||
viewModel.browserUrl?.also { url ->
|
||||
startActivity(
|
||||
BrowserActivity.newIntent(requireContext(), url, viewModel.source, viewModel.source.title),
|
||||
BrowserActivity.newIntent(
|
||||
requireContext(),
|
||||
url,
|
||||
viewModel.source,
|
||||
viewModel.source.getTitle(requireContext()),
|
||||
),
|
||||
)
|
||||
} ?: Snackbar.make(requireViewBinding().recyclerView, R.string.operation_not_supported, Snackbar.LENGTH_SHORT)
|
||||
.show()
|
||||
@@ -165,8 +171,8 @@ class RemoteListFragment : MangaListFragment(), FilterOwner {
|
||||
|
||||
const val ARG_SOURCE = "provider"
|
||||
|
||||
fun newInstance(provider: MangaSource) = RemoteListFragment().withArgs(1) {
|
||||
putSerializable(ARG_SOURCE, provider)
|
||||
fun newInstance(source: MangaSource) = RemoteListFragment().withArgs(1) {
|
||||
putString(ARG_SOURCE, source.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.LocalMangaSource
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaTags
|
||||
@@ -77,7 +79,7 @@ class MangaListActivity :
|
||||
finishAfterTransition()
|
||||
} else {
|
||||
viewBinding.buttonOrder?.setOnClickListener(this)
|
||||
title = if (src == MangaSource.LOCAL) getString(R.string.local_storage) else src.title
|
||||
title = src.getTitle(this)
|
||||
initList(src, tags)
|
||||
}
|
||||
}
|
||||
@@ -125,7 +127,7 @@ class MangaListActivity :
|
||||
} else {
|
||||
fm.commit {
|
||||
setReorderingAllowed(true)
|
||||
val fragment = if (source == MangaSource.LOCAL) {
|
||||
val fragment = if (source == LocalMangaSource) {
|
||||
LocalListFragment()
|
||||
} else {
|
||||
RemoteListFragment.newInstance(source)
|
||||
|
||||
@@ -11,8 +11,9 @@ import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.commit
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.showKeyboard
|
||||
import org.koitharu.kotatsu.databinding.ActivitySearchBinding
|
||||
@@ -28,15 +29,12 @@ class SearchActivity : BaseActivity<ActivitySearchBinding>(), SearchView.OnQuery
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivitySearchBinding.inflate(layoutInflater))
|
||||
source = intent.getSerializableExtraCompat(EXTRA_SOURCE) ?: run {
|
||||
finishAfterTransition()
|
||||
return
|
||||
}
|
||||
source = MangaSource(intent.getStringExtra(EXTRA_SOURCE))
|
||||
val query = intent.getStringExtra(EXTRA_QUERY)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged)
|
||||
with(viewBinding.searchView) {
|
||||
queryHint = getString(R.string.search_on_s, source.title)
|
||||
queryHint = getString(R.string.search_on_s, source.getTitle(context))
|
||||
setOnQueryTextListener(this@SearchActivity)
|
||||
|
||||
if (query.isNullOrBlank()) {
|
||||
@@ -52,7 +50,7 @@ class SearchActivity : BaseActivity<ActivitySearchBinding>(), SearchView.OnQuery
|
||||
viewBinding.toolbar.updatePadding(
|
||||
left = insets.left,
|
||||
right = insets.right,
|
||||
top = insets.top
|
||||
top = insets.top,
|
||||
)
|
||||
viewBinding.container.updatePadding(
|
||||
bottom = insets.bottom,
|
||||
@@ -93,7 +91,7 @@ class SearchActivity : BaseActivity<ActivitySearchBinding>(), SearchView.OnQuery
|
||||
|
||||
fun newIntent(context: Context, source: MangaSource, query: String?) =
|
||||
Intent(context, SearchActivity::class.java)
|
||||
.putExtra(EXTRA_SOURCE, source)
|
||||
.putExtra(EXTRA_SOURCE, source.name)
|
||||
.putExtra(EXTRA_QUERY, query)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class SearchFragment : MangaListFragment() {
|
||||
const val ARG_SOURCE = "source"
|
||||
|
||||
fun newInstance(source: MangaSource, query: String) = SearchFragment().withArgs(2) {
|
||||
putSerializable(ARG_SOURCE, source)
|
||||
putString(ARG_SOURCE, source.name)
|
||||
putString(ARG_QUERY, query)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.model.distinctById
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
@@ -42,7 +43,7 @@ class SearchViewModel @Inject constructor(
|
||||
) : MangaListViewModel(settings, downloadScheduler) {
|
||||
|
||||
private val query = savedStateHandle.require<String>(SearchFragment.ARG_QUERY)
|
||||
private val repository = repositoryFactory.create(savedStateHandle.require(SearchFragment.ARG_SOURCE))
|
||||
private val repository = repositoryFactory.create(MangaSource(savedStateHandle.get(SearchFragment.ARG_SOURCE)))
|
||||
private val mangaList = MutableStateFlow<List<Manga>?>(null)
|
||||
private val hasNextPage = MutableStateFlow(false)
|
||||
private val listError = MutableStateFlow<Throwable?>(null)
|
||||
|
||||
@@ -8,6 +8,7 @@ import coil.ImageLoader
|
||||
import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.ui.list.AdapterDelegateClickListenerAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
|
||||
@@ -45,7 +46,7 @@ fun searchResultsAD(
|
||||
binding.buttonMore.setOnClickListener(eventListener)
|
||||
|
||||
bind {
|
||||
binding.textViewTitle.text = item.source.title
|
||||
binding.textViewTitle.text = item.source.getTitle(context)
|
||||
binding.buttonMore.isVisible = item.hasMore
|
||||
adapter.items = item.list
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
|
||||
import org.koitharu.kotatsu.core.util.ext.toEnumSet
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
@@ -103,7 +102,7 @@ class SearchSuggestionViewModel @Inject constructor(
|
||||
suggestionJob?.cancel()
|
||||
suggestionJob = combine(
|
||||
query.debounce(DEBOUNCE_TIMEOUT),
|
||||
sourcesRepository.observeEnabledSources().map { it.toEnumSet() },
|
||||
sourcesRepository.observeEnabledSources().map { it.toSet() },
|
||||
settings.observeAsFlow(AppSettings.KEY_SEARCH_SUGGESTION_TYPES) { searchSuggestionTypes },
|
||||
::Triple,
|
||||
).mapLatest { (searchQuery, enabledSources, types) ->
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.koitharu.kotatsu.search.ui.suggestion.model
|
||||
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
@@ -51,7 +51,7 @@ sealed interface SearchSuggestionItem : ListModel {
|
||||
) : SearchSuggestionItem {
|
||||
|
||||
val isNsfw: Boolean
|
||||
get() = source.contentType == ContentType.HENTAI
|
||||
get() = source.isNsfw()
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is Source && other.source == source
|
||||
|
||||
@@ -16,8 +16,8 @@ import com.google.android.material.appbar.AppBarLayout
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.textAndVisible
|
||||
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
|
||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||
@@ -110,7 +110,7 @@ class SettingsActivity :
|
||||
ACTION_SOURCES -> SourcesSettingsFragment()
|
||||
ACTION_MANAGE_DOWNLOADS -> DownloadsSettingsFragment()
|
||||
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
|
||||
intent.getSerializableExtraCompat(EXTRA_SOURCE) ?: MangaSource.LOCAL,
|
||||
MangaSource(intent.getStringExtra(EXTRA_SOURCE)),
|
||||
)
|
||||
|
||||
ACTION_MANAGE_SOURCES -> SourcesManageFragment()
|
||||
@@ -177,6 +177,6 @@ class SettingsActivity :
|
||||
fun newSourceSettingsIntent(context: Context, source: MangaSource) =
|
||||
Intent(context, SettingsActivity::class.java)
|
||||
.setAction(ACTION_SOURCE)
|
||||
.putExtra(EXTRA_SOURCE, source)
|
||||
.putExtra(EXTRA_SOURCE, source.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
|
||||
@@ -26,7 +27,9 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setTitle(viewModel.source.title)
|
||||
context?.let { ctx ->
|
||||
setTitle(viewModel.source.getTitle(ctx))
|
||||
}
|
||||
viewModel.onResume()
|
||||
}
|
||||
|
||||
@@ -36,7 +39,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
|
||||
addPreferencesFromRepository(viewModel.repository)
|
||||
|
||||
findPreference<SwitchPreferenceCompat>(KEY_ENABLE)?.run {
|
||||
setOnPreferenceChangeListener(this@SourceSettingsFragment)
|
||||
onPreferenceChangeListener = this@SourceSettingsFragment
|
||||
}
|
||||
findPreference<Preference>(KEY_AUTH)?.run {
|
||||
val authProvider = viewModel.repository.getAuthProvider()
|
||||
@@ -101,7 +104,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
|
||||
const val EXTRA_SOURCE = "source"
|
||||
|
||||
fun newInstance(source: MangaSource) = SourceSettingsFragment().withArgs(1) {
|
||||
putSerializable(EXTRA_SOURCE, source)
|
||||
putString(EXTRA_SOURCE, source.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import okhttp3.HttpUrl
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
@@ -16,10 +17,8 @@ import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||
import org.koitharu.kotatsu.core.util.ext.call
|
||||
import org.koitharu.kotatsu.core.util.ext.require
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -30,7 +29,7 @@ class SourceSettingsViewModel @Inject constructor(
|
||||
private val mangaSourcesRepository: MangaSourcesRepository,
|
||||
) : BaseViewModel(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
val source = savedStateHandle.require<MangaSource>(SourceSettingsFragment.EXTRA_SOURCE)
|
||||
val source = MangaSource(savedStateHandle.get<String>(SourceSettingsFragment.EXTRA_SOURCE))
|
||||
val repository = mangaRepositoryFactory.create(source) as RemoteMangaRepository
|
||||
|
||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||
|
||||
@@ -18,15 +18,16 @@ import org.koitharu.kotatsu.browser.BrowserCallback
|
||||
import org.koitharu.kotatsu.browser.BrowserClient
|
||||
import org.koitharu.kotatsu.browser.ProgressChromeClient
|
||||
import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.util.TaggedActivityResult
|
||||
import org.koitharu.kotatsu.core.util.ext.configureForParser
|
||||
import org.koitharu.kotatsu.core.util.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.databinding.ActivityBrowserBinding
|
||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
@@ -46,8 +47,8 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
if (!setContentViewWebViewSafe { ActivityBrowserBinding.inflate(layoutInflater) }) {
|
||||
return
|
||||
}
|
||||
val source = intent?.getSerializableExtraCompat<MangaSource>(EXTRA_SOURCE)
|
||||
if (source == null) {
|
||||
val source = MangaSource(intent?.getStringExtra(EXTRA_SOURCE))
|
||||
if (source !is MangaParserSource) {
|
||||
finishAfterTransition()
|
||||
return
|
||||
}
|
||||
@@ -148,7 +149,7 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
|
||||
fun newIntent(context: Context, source: MangaSource): Intent {
|
||||
return Intent(context, SourceAuthActivity::class.java)
|
||||
.putExtra(EXTRA_SOURCE, source)
|
||||
.putExtra(EXTRA_SOURCE, source.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ package org.koitharu.kotatsu.settings.sources.catalog
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
|
||||
sealed interface SourceCatalogItem : ListModel {
|
||||
|
||||
data class Source(
|
||||
val source: MangaSource,
|
||||
val source: MangaParserSource,
|
||||
) : SourceCatalogItem {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.settings.sources.catalog
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import coil.ImageLoader
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
|
||||
@@ -23,6 +24,6 @@ class SourcesCatalogAdapter(
|
||||
}
|
||||
|
||||
override fun getSectionText(context: Context, position: Int): CharSequence? {
|
||||
return (items.getOrNull(position) as? SourceCatalogItem.Source)?.source?.title?.take(1)
|
||||
return (items.getOrNull(position) as? SourceCatalogItem.Source)?.source?.getTitle(context)?.take(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.koitharu.kotatsu.settings.sources.manage
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.InvalidationTracker
|
||||
import dagger.hilt.android.ViewModelLifecycle
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.android.scopes.ViewModelScoped
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
@@ -14,10 +16,10 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.TABLE_SOURCES
|
||||
import org.koitharu.kotatsu.core.model.getTitle
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.lifecycleScope
|
||||
import org.koitharu.kotatsu.core.util.ext.toEnumSet
|
||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||
import org.koitharu.kotatsu.explore.data.SourcesSortOrder
|
||||
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||
@@ -26,6 +28,7 @@ import javax.inject.Inject
|
||||
@ViewModelScoped
|
||||
class SourcesListProducer @Inject constructor(
|
||||
lifecycle: ViewModelLifecycle,
|
||||
@ApplicationContext private val context: Context,
|
||||
private val repository: MangaSourcesRepository,
|
||||
private val settings: AppSettings,
|
||||
) : InvalidationTracker.Observer(TABLE_SOURCES) {
|
||||
@@ -64,10 +67,10 @@ class SourcesListProducer @Inject constructor(
|
||||
val isNsfwDisabled = settings.isNsfwContentDisabled
|
||||
val isReorderAvailable = settings.sourcesSortOrder == SourcesSortOrder.MANUAL
|
||||
val withTip = isReorderAvailable && settings.isTipEnabled(TIP_REORDER)
|
||||
val enabledSet = enabledSources.toEnumSet()
|
||||
val enabledSet = enabledSources.toSet()
|
||||
if (query.isNotEmpty()) {
|
||||
return enabledSources.mapNotNull {
|
||||
if (!it.title.contains(query, ignoreCase = true)) {
|
||||
if (!it.getTitle(context).contains(query, ignoreCase = true)) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
SourceConfigItem.SourceItem(
|
||||
|
||||
@@ -2,8 +2,8 @@ package org.koitharu.kotatsu.settings.sources.model
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import org.koitharu.kotatsu.core.model.isNsfw
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
sealed interface SourceConfigItem : ListModel {
|
||||
@@ -16,7 +16,7 @@ sealed interface SourceConfigItem : ListModel {
|
||||
) : SourceConfigItem {
|
||||
|
||||
val isNsfw: Boolean
|
||||
get() = source.contentType == ContentType.HENTAI
|
||||
get() = source.isNsfw()
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is SourceItem && other.source == source
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -42,7 +42,7 @@ class JsonSerializerTest {
|
||||
largeCoverUrl = null,
|
||||
state = MangaState.FINISHED.name,
|
||||
author = "RERE",
|
||||
source = MangaSource.DUMMY.name,
|
||||
source = MangaParserSource.DUMMY.name,
|
||||
)
|
||||
val json = JsonSerializer(entity).toJson()
|
||||
val result = JsonDeserializer(json).toMangaEntity()
|
||||
@@ -55,7 +55,7 @@ class JsonSerializerTest {
|
||||
id = 934023534,
|
||||
title = "Adventure",
|
||||
key = "adventure",
|
||||
source = MangaSource.DUMMY.name,
|
||||
source = MangaParserSource.DUMMY.name,
|
||||
)
|
||||
val json = JsonSerializer(entity).toJson()
|
||||
val result = JsonDeserializer(json).toTagEntity()
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.domain
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||
import kotlin.random.Random
|
||||
|
||||
@@ -73,6 +73,6 @@ class ChapterPagesTest {
|
||||
preview = null,
|
||||
chapterId = chapterId,
|
||||
index = Random.nextInt(),
|
||||
source = MangaSource.DUMMY,
|
||||
source = MangaParserSource.DUMMY,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user