Sources settings
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
@@ -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(
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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.*
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ->
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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
|
||||||
|
|||||||
10
app/src/main/res/xml/pref_source.xml
Normal file
10
app/src/main/res/xml/pref_source.xml
Normal 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>
|
||||||
Reference in New Issue
Block a user