Sources settings

This commit is contained in:
Koitharu
2020-03-14 10:20:56 +02:00
parent 68b196de52
commit 3c4e29149f
32 changed files with 178 additions and 106 deletions

View File

@@ -13,9 +13,9 @@ import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin import org.koin.core.context.startKoin
import org.koin.dsl.module import org.koin.dsl.module
import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.http.persistentcookiejar.PersistentCookieJar import org.koitharu.kotatsu.core.local.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.http.persistentcookiejar.cache.SetCookieCache import org.koitharu.kotatsu.core.local.cookies.cache.SetCookieCache
import org.koitharu.kotatsu.core.http.persistentcookiejar.persistence.SharedPrefsCookiePersistor import org.koitharu.kotatsu.core.local.cookies.persistence.SharedPrefsCookiePersistor
import org.koitharu.kotatsu.core.local.CbzFetcher import org.koitharu.kotatsu.core.local.CbzFetcher
import org.koitharu.kotatsu.core.local.PagesCache import org.koitharu.kotatsu.core.local.PagesCache
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
@@ -47,19 +47,15 @@ class KotatsuApp : Application() {
.cache(CacheUtils.createHttpCache(applicationContext)) .cache(CacheUtils.createHttpCache(applicationContext))
.build() .build()
} }
}, module {
single {
MangaLoaderContext()
}
}, module {
single { single {
mangaDb().build() mangaDb().build()
} }
}, module { single {
MangaLoaderContext()
}
factory { factory {
AppSettings(applicationContext) AppSettings(applicationContext)
} }
}, module {
single { single {
PagesCache(applicationContext) PagesCache(applicationContext)
} }

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar package org.koitharu.kotatsu.core.local.cookies
import okhttp3.CookieJar import okhttp3.CookieJar

View File

@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar package org.koitharu.kotatsu.core.local.cookies
import org.koitharu.kotatsu.core.http.persistentcookiejar.persistence.CookiePersistor import org.koitharu.kotatsu.core.local.cookies.persistence.CookiePersistor
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.HttpUrl import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.http.persistentcookiejar.cache.CookieCache import org.koitharu.kotatsu.core.local.cookies.cache.CookieCache
import java.util.* import java.util.*
class PersistentCookieJar( class PersistentCookieJar(

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.cache package org.koitharu.kotatsu.core.local.cookies.cache
import okhttp3.Cookie import okhttp3.Cookie

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.cache package org.koitharu.kotatsu.core.local.cookies.cache
import okhttp3.Cookie import okhttp3.Cookie
import java.util.* import java.util.*

View File

@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.cache package org.koitharu.kotatsu.core.local.cookies.cache
import okhttp3.Cookie import okhttp3.Cookie
import org.koitharu.kotatsu.core.http.persistentcookiejar.cache.IdentifiableCookie.Companion.decorateAll import org.koitharu.kotatsu.core.local.cookies.cache.IdentifiableCookie.Companion.decorateAll
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.persistence package org.koitharu.kotatsu.core.local.cookies.persistence
import okhttp3.Cookie import okhttp3.Cookie

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.persistence package org.koitharu.kotatsu.core.local.cookies.persistence
import android.util.Log import android.util.Log
import okhttp3.Cookie import okhttp3.Cookie

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.koitharu.kotatsu.core.http.persistentcookiejar.persistence package org.koitharu.kotatsu.core.local.cookies.persistence
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context

View File

@@ -1,16 +0,0 @@
package org.koitharu.kotatsu.core.parser
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.domain.MangaLoaderContext
abstract class BaseMangaRepository(protected val loaderContext: MangaLoaderContext) :
MangaRepository {
override val sortOrders: Set<SortOrder> get() = emptySet()
override suspend fun getPageFullUrl(page: MangaPage) : String = page.url
override suspend fun getTags(): Set<MangaTag> = emptySet()
}

View File

@@ -4,10 +4,10 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.core.net.toUri import androidx.core.net.toUri
import org.koin.core.KoinComponent
import org.koin.core.inject import org.koin.core.inject
import org.koitharu.kotatsu.core.local.CbzFilter import org.koitharu.kotatsu.core.local.CbzFilter
import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.domain.local.MangaIndex import org.koitharu.kotatsu.domain.local.MangaIndex
import org.koitharu.kotatsu.domain.local.MangaZip import org.koitharu.kotatsu.domain.local.MangaZip
import org.koitharu.kotatsu.utils.AlphanumComparator import org.koitharu.kotatsu.utils.AlphanumComparator
@@ -19,9 +19,9 @@ import java.util.*
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
class LocalMangaRepository(loaderContext: MangaLoaderContext) : BaseMangaRepository(loaderContext) { class LocalMangaRepository : MangaRepository, KoinComponent {
private val context by loaderContext.inject<Context>() private val context by inject<Context>()
override suspend fun getList( override suspend fun getList(
offset: Int, offset: Int,
@@ -114,6 +114,12 @@ class LocalMangaRepository(loaderContext: MangaLoaderContext) : BaseMangaReposit
return list.firstOrNull() return list.firstOrNull()
} }
override val sortOrders = emptySet<SortOrder>()
override suspend fun getPageFullUrl(page: MangaPage) = page.url
override suspend fun getTags() = emptySet<MangaTag>()
companion object { companion object {
fun isFileSupported(name: String): Boolean { fun isFileSupported(name: String): Boolean {

View File

@@ -0,0 +1,27 @@
package org.koitharu.kotatsu.core.parser
import org.koin.core.KoinComponent
import org.koin.core.inject
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.domain.MangaLoaderContext
abstract class RemoteMangaRepository : MangaRepository, KoinComponent {
protected abstract val source: MangaSource
protected val loaderContext by inject<MangaLoaderContext>()
protected val conf by lazy(LazyThreadSafetyMode.NONE) {
loaderContext.getSettings(source)
}
override val sortOrders: Set<SortOrder> get() = emptySet()
override suspend fun getPageFullUrl(page: MangaPage): String = page.url
override suspend fun getTags(): Set<MangaTag> = emptySet()
abstract fun onCreatePreferences(): Set<Int>
}

View File

@@ -1,17 +1,14 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.BaseMangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.*
abstract class ChanRepository( abstract class ChanRepository : RemoteMangaRepository() {
private val source: MangaSource,
loaderContext: MangaLoaderContext
) : BaseMangaRepository(loaderContext) {
protected abstract val domain: String protected abstract val defaultDomain: String
override val sortOrders = setOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.ALPHABETICAL) override val sortOrders = setOf(SortOrder.NEWEST, SortOrder.POPULARITY, SortOrder.ALPHABETICAL)
@@ -21,12 +18,13 @@ abstract class ChanRepository(
sortOrder: SortOrder?, sortOrder: SortOrder?,
tag: MangaTag? tag: MangaTag?
): List<Manga> { ): List<Manga> {
val domain = conf.getDomain(defaultDomain)
val url = when { val url = when {
query != null -> "https://$domain/?do=search&subaction=search&story=${query.urlEncoded()}" query != null -> "https://$domain/?do=search&subaction=search&story=${query.urlEncoded()}"
tag != null -> "https://$domain/tags/${tag.key}&n=${getSortKey2(sortOrder)}?offset=$offset" tag != null -> "https://$domain/tags/${tag.key}&n=${getSortKey2(sortOrder)}?offset=$offset"
else -> "https://$domain/${getSortKey(sortOrder)}?offset=$offset" else -> "https://$domain/${getSortKey(sortOrder)}?offset=$offset"
} }
val doc = loaderContext.get(url).parseHtml() val doc = loaderContext.httpGet(url).parseHtml()
val root = doc.body().selectFirst("div.main_fon").getElementById("content") val root = doc.body().selectFirst("div.main_fon").getElementById("content")
?: throw ParseException("Cannot find root") ?: throw ParseException("Cannot find root")
return root.select("div.content_row").mapNotNull { row -> return root.select("div.content_row").mapNotNull { row ->
@@ -60,7 +58,8 @@ abstract class ChanRepository(
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = loaderContext.get(manga.url).parseHtml() val domain = conf.getDomain(defaultDomain)
val doc = loaderContext.httpGet(manga.url).parseHtml()
val root = val root =
doc.body().getElementById("dle-content") ?: throw ParseException("Cannot find root") doc.body().getElementById("dle-content") ?: throw ParseException("Cannot find root")
return manga.copy( return manga.copy(
@@ -83,7 +82,7 @@ abstract class ChanRepository(
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = loaderContext.get(chapter.url).parseHtml() val doc = loaderContext.httpGet(chapter.url).parseHtml()
val scripts = doc.select("script") val scripts = doc.select("script")
for (script in scripts) { for (script in scripts) {
val data = script.html() val data = script.html()
@@ -107,7 +106,8 @@ abstract class ChanRepository(
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getTags(): Set<MangaTag> {
val doc = loaderContext.get("https://$domain/catalog").parseHtml() val domain = conf.getDomain(defaultDomain)
val doc = loaderContext.httpGet("https://$domain/catalog").parseHtml()
val root = doc.body().selectFirst("div.main_fon").getElementById("side") val root = doc.body().selectFirst("div.main_fon").getElementById("side")
.select("ul").last() .select("ul").last()
return root.select("li.sidetag").map { li -> return root.select("li.sidetag").map { li ->
@@ -120,6 +120,8 @@ abstract class ChanRepository(
}.toSet() }.toSet()
} }
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) = private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder ?: sortOrders.minBy { it.ordinal }) { when (sortOrder ?: sortOrders.minBy { it.ordinal }) {
SortOrder.ALPHABETICAL -> "catalog" SortOrder.ALPHABETICAL -> "catalog"

View File

@@ -1,18 +1,14 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.ParseException import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.* import org.koitharu.kotatsu.core.model.*
import org.koitharu.kotatsu.core.parser.BaseMangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.utils.ext.* import org.koitharu.kotatsu.utils.ext.*
abstract class GroupleRepository( abstract class GroupleRepository : RemoteMangaRepository() {
private val source: MangaSource,
loaderContext: MangaLoaderContext
) :
BaseMangaRepository(loaderContext) {
protected abstract val domain: String protected abstract val defaultDomain: String
override val sortOrders = setOf( override val sortOrders = setOf(
SortOrder.UPDATED, SortOrder.POPULARITY, SortOrder.UPDATED, SortOrder.POPULARITY,
@@ -26,13 +22,14 @@ abstract class GroupleRepository(
sortOrder: SortOrder?, sortOrder: SortOrder?,
tag: MangaTag? tag: MangaTag?
): List<Manga> { ): List<Manga> {
val domain = conf.getDomain(defaultDomain)
val doc = when { val doc = when {
!query.isNullOrEmpty() -> loaderContext.post( !query.isNullOrEmpty() -> loaderContext.httpPost(
"https://$domain/search", "https://$domain/search",
mapOf("q" to query) mapOf("q" to query)
) )
tag == null -> loaderContext.get("https://$domain/list?sortType=${getSortKey(sortOrder)}&offset=$offset") tag == null -> loaderContext.httpGet("https://$domain/list?sortType=${getSortKey(sortOrder)}&offset=$offset")
else -> loaderContext.get( else -> loaderContext.httpGet(
"https://$domain/list/genre/${tag.key}?sortType=${getSortKey( "https://$domain/list/genre/${tag.key}?sortType=${getSortKey(
sortOrder sortOrder
)}&offset=$offset" )}&offset=$offset"
@@ -86,7 +83,8 @@ abstract class GroupleRepository(
} }
override suspend fun getDetails(manga: Manga): Manga { override suspend fun getDetails(manga: Manga): Manga {
val doc = loaderContext.get(manga.url).parseHtml() val domain = conf.getDomain(defaultDomain)
val doc = loaderContext.httpGet(manga.url).parseHtml()
val root = doc.body().getElementById("mangaBox") ?: throw ParseException("Cannot find root") val root = doc.body().getElementById("mangaBox") ?: throw ParseException("Cannot find root")
return manga.copy( return manga.copy(
description = root.selectFirst("div.manga-description").firstChild()?.html(), description = root.selectFirst("div.manga-description").firstChild()?.html(),
@@ -109,7 +107,7 @@ abstract class GroupleRepository(
} }
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> { override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
val doc = loaderContext.get(chapter.url + "?mtr=1").parseHtml() val doc = loaderContext.httpGet(chapter.url + "?mtr=1").parseHtml()
val scripts = doc.select("script") val scripts = doc.select("script")
for (script in scripts) { for (script in scripts) {
val data = script.html() val data = script.html()
@@ -135,7 +133,8 @@ abstract class GroupleRepository(
} }
override suspend fun getTags(): Set<MangaTag> { override suspend fun getTags(): Set<MangaTag> {
val doc = loaderContext.get("https://$domain/list/genres/sort_name").parseHtml() val domain = conf.getDomain(defaultDomain)
val doc = loaderContext.httpGet("https://$domain/list/genres/sort_name").parseHtml()
val root = doc.body().getElementById("mangaBox").selectFirst("div.leftContent") val root = doc.body().getElementById("mangaBox").selectFirst("div.leftContent")
.selectFirst("table.table") .selectFirst("table.table")
return root.select("a.element-link").map { a -> return root.select("a.element-link").map { a ->
@@ -147,6 +146,8 @@ abstract class GroupleRepository(
}.toSet() }.toSet()
} }
override fun onCreatePreferences() = setOf(R.string.key_parser_domain)
private fun getSortKey(sortOrder: SortOrder?) = private fun getSortKey(sortOrder: SortOrder?) =
when (sortOrder ?: sortOrders.minBy { it.ordinal }) { when (sortOrder ?: sortOrders.minBy { it.ordinal }) {
SortOrder.ALPHABETICAL -> "name" SortOrder.ALPHABETICAL -> "name"

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class HenChanRepository(loaderContext: MangaLoaderContext) : class HenChanRepository : ChanRepository() {
ChanRepository(MangaSource.HENCHAN, loaderContext) {
override val domain: String = "h-chan.me" override val defaultDomain = "h-chan.me"
override val source = MangaSource.HENCHAN
} }

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class MangaChanRepository(loaderContext: MangaLoaderContext) : class MangaChanRepository : ChanRepository() {
ChanRepository(MangaSource.MANGACHAN, loaderContext) {
override val domain: String = "manga-chan.me" override val defaultDomain = "manga-chan.me"
override val source = MangaSource.MANGACHAN
} }

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class MintMangaRepository(loaderContext: MangaLoaderContext) : class MintMangaRepository : GroupleRepository() {
GroupleRepository(MangaSource.MINTMANGA, loaderContext) {
override val domain: String = "mintmanga.live" override val source = MangaSource.MINTMANGA
override val defaultDomain: String = "mintmanga.live"
} }

View File

@@ -1,11 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class ReadmangaRepository(loaderContext: MangaLoaderContext) : class ReadmangaRepository : GroupleRepository() {
GroupleRepository(MangaSource.READMANGA_RU, loaderContext) {
override val domain = "readmanga.me"
override val defaultDomain = "readmanga.me"
override val source = MangaSource.READMANGA_RU
} }

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class SelfMangaRepository(loaderContext: MangaLoaderContext) : class SelfMangaRepository : GroupleRepository() {
GroupleRepository(MangaSource.SELFMANGA, loaderContext) {
override val domain: String = "selfmanga.ru" override val defaultDomain = "selfmanga.ru"
override val source = MangaSource.SELFMANGA
} }

View File

@@ -1,10 +1,9 @@
package org.koitharu.kotatsu.core.parser.site package org.koitharu.kotatsu.core.parser.site
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.domain.MangaLoaderContext
class YaoiChanRepository(loaderContext: MangaLoaderContext) : class YaoiChanRepository : ChanRepository() {
ChanRepository(MangaSource.YAOICHAN, loaderContext) {
override val domain: String = "yaoi-chan.me" override val source = MangaSource.YAOICHAN
override val defaultDomain = "yaoi-chan.me"
} }

View File

@@ -0,0 +1,15 @@
package org.koitharu.kotatsu.core.prefs
import android.content.Context
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource
class SourceConfig(context: Context, source: MangaSource) {
private val prefs = context.getSharedPreferences(source.name, Context.MODE_PRIVATE)
private val keyDomain = context.getString(R.string.key_parser_domain)
fun getDomain(defaultValue: String) = prefs.getString(keyDomain, defaultValue) ?: defaultValue
}

View File

@@ -5,14 +5,17 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get
import org.koin.core.inject import org.koin.core.inject
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.SourceConfig
import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.await
class MangaLoaderContext : KoinComponent { class MangaLoaderContext : KoinComponent {
private val okHttp by inject<OkHttpClient>() private val okHttp by inject<OkHttpClient>()
suspend fun get(url: String, block: (Request.Builder.() -> Unit)? = null): Response { suspend fun httpGet(url: String, block: (Request.Builder.() -> Unit)? = null): Response {
val request = Request.Builder() val request = Request.Builder()
.get() .get()
.url(url) .url(url)
@@ -22,7 +25,7 @@ class MangaLoaderContext : KoinComponent {
return okHttp.newCall(request.build()).await() return okHttp.newCall(request.build()).await()
} }
suspend fun post( suspend fun httpPost(
url: String, url: String,
form: Map<String, String>, form: Map<String, String>,
block: (Request.Builder.() -> Unit)? = null block: (Request.Builder.() -> Unit)? = null
@@ -39,4 +42,6 @@ class MangaLoaderContext : KoinComponent {
} }
return okHttp.newCall(request.build()).await() return okHttp.newCall(request.build()).await()
} }
fun getSettings(source: MangaSource) = SourceConfig(get(), source)
} }

View File

@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.domain
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.get import org.koin.core.get
import org.koin.core.inject
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.LocalMangaRepository import org.koitharu.kotatsu.core.parser.LocalMangaRepository
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
@@ -10,8 +9,6 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
object MangaProviderFactory : KoinComponent { object MangaProviderFactory : KoinComponent {
private val loaderContext by inject<MangaLoaderContext>()
val sources: List<MangaSource> val sources: List<MangaSource>
get() { get() {
val list = MangaSource.values().toList() - MangaSource.LOCAL val list = MangaSource.values().toList() - MangaSource.LOCAL
@@ -22,10 +19,9 @@ object MangaProviderFactory : KoinComponent {
} }
} }
fun createLocal() = LocalMangaRepository(loaderContext) fun createLocal() = LocalMangaRepository()
fun create(source: MangaSource): MangaRepository { fun create(source: MangaSource): MangaRepository {
val constructor = source.cls.getConstructor(MangaLoaderContext::class.java) return source.cls.newInstance()
return constructor.newInstance(loaderContext)
} }
} }

View File

@@ -30,6 +30,7 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) { imageView_cover.load(manga.largeCoverUrl ?: manga.coverUrl) {
fallback(R.drawable.ic_placeholder) fallback(R.drawable.ic_placeholder)
crossfade(true) crossfade(true)
lifecycle(this@MangaDetailsFragment)
} }
textView_title.text = manga.title textView_title.text = manga.title
textView_subtitle.textAndVisible = manga.altTitle textView_subtitle.textAndVisible = manga.altTitle

View File

@@ -5,7 +5,6 @@ import android.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.collection.arrayMapOf import androidx.collection.arrayMapOf
import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.SeekBarPreference import androidx.preference.SeekBarPreference
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -21,8 +20,6 @@ class AppearanceSettingsFragment : BasePreferenceFragment(R.string.appearance),
findPreference<Preference>(R.string.key_list_mode)?.summary = findPreference<Preference>(R.string.key_list_mode)?.summary =
listModes[settings.listMode]?.let(::getString) listModes[settings.listMode]?.let(::getString)
findPreference<ListPreference>(R.string.key_theme)?.summaryProvider =
ListPreference.SimpleSummaryProvider.getInstance()
findPreference<SeekBarPreference>(R.string.key_grid_size)?.run { findPreference<SeekBarPreference>(R.string.key_grid_size)?.run {
summary = "%d%%".format(value) summary = "%d%%".format(value)
setOnPreferenceChangeListener { preference, newValue -> setOnPreferenceChangeListener { preference, newValue ->

View File

@@ -1,18 +1,25 @@
package org.koitharu.kotatsu.ui.settings package org.koitharu.kotatsu.ui.settings
import android.os.Bundle import android.os.Bundle
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.ui.settings.utils.EditTextSummaryProvider
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class SourceSettingsFragment : PreferenceFragmentCompat(), KoinComponent { class SourceSettingsFragment : PreferenceFragmentCompat(), KoinComponent {
private lateinit var source: MangaSource private val source by lazy(LazyThreadSafetyMode.NONE) {
requireArguments().getParcelable<MangaSource>(EXTRA_SOURCE)!!
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
source = requireArguments().getParcelable(EXTRA_SOURCE)!! preferenceManager.sharedPreferencesName = source.name
} }
override fun onResume() { override fun onResume() {
@@ -21,7 +28,15 @@ class SourceSettingsFragment : PreferenceFragmentCompat(), KoinComponent {
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
val repo = MangaProviderFactory.create(source) as? RemoteMangaRepository ?: return
val keys = repo.onCreatePreferences().map(::getString)
addPreferencesFromResource(R.xml.pref_source)
for (i in 0 until preferenceScreen.preferenceCount) {
val pref = preferenceScreen.getPreference(i)
pref.isVisible = pref.key in keys
}
findPreference<EditTextPreference>(getString(R.string.key_parser_domain))?.summaryProvider =
EditTextSummaryProvider(R.string._default)
} }
companion object { companion object {

View File

@@ -0,0 +1,17 @@
package org.koitharu.kotatsu.ui.settings.utils
import androidx.annotation.StringRes
import androidx.preference.EditTextPreference
import androidx.preference.Preference
class EditTextSummaryProvider(@StringRes private val emptySummaryId: Int) :
Preference.SummaryProvider<EditTextPreference> {
override fun provideSummary(preference: EditTextPreference): CharSequence {
return if (preference.text.isNullOrEmpty()) {
preference.context.getString(emptySummaryId)
} else {
preference.text
}
}
}

View File

@@ -100,6 +100,8 @@
<string name="clear_search_history">Очистить историю поиска</string> <string name="clear_search_history">Очистить историю поиска</string>
<string name="search_history_cleared">История поиска очищена</string> <string name="search_history_cleared">История поиска очищена</string>
<string name="gestures_only">Только жесты</string> <string name="gestures_only">Только жесты</string>
<string name="internal_storage">Internal storage</string> <string name="internal_storage">Внутренний накопитель</string>
<string name="external_storage">External storage</string> <string name="external_storage">Внешнее хранилище</string>
<string name="domain">Домен</string>
<string name="_default">По умолчанию</string>
</resources> </resources>

View File

@@ -10,6 +10,8 @@
<string name="key_reading_history_clear">reading_history_clear</string> <string name="key_reading_history_clear">reading_history_clear</string>
<string name="key_grid_size">grid_size</string> <string name="key_grid_size">grid_size</string>
<string name="key_reader_switchers">reader_switchers</string> <string name="key_reader_switchers">reader_switchers</string>
<string name="key_parser_domain">domain</string>
<string-array name="values_theme"> <string-array name="values_theme">
<item>-1</item> <item>-1</item>
<item>1</item> <item>1</item>

View File

@@ -103,4 +103,6 @@
<string name="gestures_only">Gestures only</string> <string name="gestures_only">Gestures only</string>
<string name="internal_storage">Internal storage</string> <string name="internal_storage">Internal storage</string>
<string name="external_storage">External storage</string> <string name="external_storage">External storage</string>
<string name="domain">Domain</string>
<string name="_default">Default</string>
</resources> </resources>

View File

@@ -9,6 +9,7 @@
android:entryValues="@array/values_theme" android:entryValues="@array/values_theme"
android:key="@string/key_theme" android:key="@string/key_theme"
android:title="@string/theme" android:title="@string/theme"
app:useSimpleSummaryProvider="true"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<Preference <Preference

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
android:key="@string/key_parser_domain"
android:title="@string/domain"
app:iconSpaceReserved="false" />
</PreferenceScreen>