Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
080c2724cd | ||
|
|
43872ffe01 | ||
|
|
5cfad9ab8a | ||
|
|
866f9272ef | ||
|
|
f5a6e1e124 | ||
|
|
5595bc6971 | ||
|
|
e6ed353211 | ||
|
|
4e10908015 | ||
|
|
087ececfdd | ||
|
|
c090018acd | ||
|
|
5f6256a5c6 | ||
|
|
9e6be12707 | ||
|
|
737ca4a916 | ||
|
|
b2958d03e4 | ||
|
|
af8550744f | ||
|
|
2f5fd71bb1 | ||
|
|
271750ad93 | ||
|
|
0281c09dde | ||
|
|
f2ac3c331c | ||
|
|
4fc56f9786 | ||
|
|
a13c498d00 | ||
|
|
e15934bdc6 |
@@ -8,15 +8,15 @@ plugins {
|
||||
|
||||
android {
|
||||
compileSdk = 33
|
||||
buildToolsVersion = '33.0.1'
|
||||
buildToolsVersion = '33.0.2'
|
||||
namespace = 'org.koitharu.kotatsu'
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'org.koitharu.kotatsu'
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
versionCode 518
|
||||
versionName '4.4.2'
|
||||
versionCode 520
|
||||
versionName '4.4.4'
|
||||
generatedDensities = []
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -25,15 +25,6 @@ android {
|
||||
arg 'room.schemaLocation', "$projectDir/schemas".toString()
|
||||
}
|
||||
}
|
||||
|
||||
// define this values in your local.properties file
|
||||
buildConfigField 'String', 'SHIKIMORI_CLIENT_ID', "\"${localProperty('shikimori.clientId')}\""
|
||||
buildConfigField 'String', 'SHIKIMORI_CLIENT_SECRET', "\"${localProperty('shikimori.clientSecret')}\""
|
||||
buildConfigField 'String', 'ANILIST_CLIENT_ID', "\"${localProperty('anilist.clientId')}\""
|
||||
buildConfigField 'String', 'ANILIST_CLIENT_SECRET', "\"${localProperty('anilist.clientSecret')}\""
|
||||
buildConfigField 'String', 'MAL_CLIENT_ID', "\"${localProperty('mal.clientId')}\""
|
||||
resValue "string", "acra_login", "${localProperty('acra.login')}"
|
||||
resValue "string", "acra_password", "${localProperty('acra.password')}"
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
@@ -87,7 +78,7 @@ afterEvaluate {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:1093584202') {
|
||||
implementation('com.github.KotatsuApp:kotatsu-parsers:e8d299782b') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ interface AppModule {
|
||||
writeTimeout(20, TimeUnit.SECONDS)
|
||||
cookieJar(cookieJar)
|
||||
dns(DoHManager(cache, settings))
|
||||
if (settings.isSSLBypassEnabled) {
|
||||
bypassSSLErrors()
|
||||
}
|
||||
cache(cache)
|
||||
addInterceptor(GZipInterceptor())
|
||||
addInterceptor(commonHeadersInterceptor)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.koitharu.kotatsu.core.network
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import okhttp3.OkHttpClient
|
||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||
import java.security.SecureRandom
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
import javax.net.ssl.X509TrustManager
|
||||
|
||||
@SuppressLint("CustomX509TrustManager")
|
||||
fun OkHttpClient.Builder.bypassSSLErrors() = also { builder ->
|
||||
runCatching {
|
||||
val trustAllCerts = object : X509TrustManager {
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) = Unit
|
||||
|
||||
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) = Unit
|
||||
|
||||
override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
|
||||
}
|
||||
val sslContext = SSLContext.getInstance("SSL")
|
||||
sslContext.init(null, arrayOf(trustAllCerts), SecureRandom())
|
||||
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
|
||||
builder.sslSocketFactory(sslSocketFactory, trustAllCerts)
|
||||
builder.hostnameVerifier { _, _ -> true }
|
||||
}.onFailure {
|
||||
it.printStackTraceDebug()
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
val dnsOverHttps: DoHProvider
|
||||
get() = prefs.getEnumValue(KEY_DOH, DoHProvider.NONE)
|
||||
|
||||
val isSSLBypassEnabled: Boolean
|
||||
get() = prefs.getBoolean(KEY_SSL_BYPASS, false)
|
||||
|
||||
var localListOrder: SortOrder
|
||||
get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST)
|
||||
set(value) = prefs.edit { putEnumValue(KEY_LOCAL_LIST_ORDER, value) }
|
||||
@@ -380,6 +383,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_LOGS_SHARE = "logs_share"
|
||||
const val KEY_SOURCES_GRID = "sources_grid"
|
||||
const val KEY_UPDATES_UNSTABLE = "updates_unstable"
|
||||
const val KEY_SSL_BYPASS = "ssl_bypass"
|
||||
|
||||
// About
|
||||
const val KEY_APP_UPDATE = "app_update"
|
||||
|
||||
@@ -60,6 +60,9 @@ fun mangaListDetailedItemAD(
|
||||
lifecycle(lifecycleOwner)
|
||||
enqueueWith(coil)
|
||||
}
|
||||
if (payloads.isEmpty()) {
|
||||
binding.scrollViewTags.scrollTo(0, 0)
|
||||
}
|
||||
binding.chipsTags.setChips(item.tags)
|
||||
binding.ratingBar.isVisible = item.manga.hasRating
|
||||
binding.ratingBar.rating = binding.ratingBar.numStars * item.manga.rating
|
||||
|
||||
@@ -36,6 +36,7 @@ object ScrobblingModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideShikimoriRepository(
|
||||
@ApplicationContext context: Context,
|
||||
@ScrobblerType(ScrobblerService.SHIKIMORI) storage: ScrobblerStorage,
|
||||
database: MangaDatabase,
|
||||
authenticator: ShikimoriAuthenticator,
|
||||
@@ -47,12 +48,13 @@ object ScrobblingModule {
|
||||
addInterceptor(CurlLoggingInterceptor())
|
||||
}
|
||||
}.build()
|
||||
return ShikimoriRepository(okHttp, storage, database)
|
||||
return ShikimoriRepository(context, okHttp, storage, database)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMALRepository(
|
||||
@ApplicationContext context: Context,
|
||||
@ScrobblerType(ScrobblerService.MAL) storage: ScrobblerStorage,
|
||||
database: MangaDatabase,
|
||||
authenticator: MALAuthenticator,
|
||||
@@ -64,12 +66,13 @@ object ScrobblingModule {
|
||||
addInterceptor(CurlLoggingInterceptor())
|
||||
}
|
||||
}.build()
|
||||
return MALRepository(okHttp, storage, database)
|
||||
return MALRepository(context, okHttp, storage, database)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAniListRepository(
|
||||
@ApplicationContext context: Context,
|
||||
@ScrobblerType(ScrobblerService.ANILIST) storage: ScrobblerStorage,
|
||||
database: MangaDatabase,
|
||||
authenticator: AniListAuthenticator,
|
||||
@@ -81,7 +84,7 @@ object ScrobblingModule {
|
||||
addInterceptor(CurlLoggingInterceptor())
|
||||
}
|
||||
}.build()
|
||||
return AniListRepository(okHttp, storage, database)
|
||||
return AniListRepository(context, okHttp, storage, database)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package org.koitharu.kotatsu.scrobbling.anilist.data
|
||||
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.parsers.exception.GraphQLException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
@@ -15,6 +17,7 @@ import org.koitharu.kotatsu.parsers.util.json.getStringOrNull
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.parsers.util.toIntUp
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||
@@ -32,13 +35,17 @@ private const val REQUEST_MUTATION = "mutation"
|
||||
private const val KEY_SCORE_FORMAT = "score_format"
|
||||
|
||||
class AniListRepository(
|
||||
@ApplicationContext context: Context,
|
||||
private val okHttp: OkHttpClient,
|
||||
private val storage: ScrobblerStorage,
|
||||
private val db: MangaDatabase,
|
||||
) : org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository {
|
||||
) : ScrobblerRepository {
|
||||
|
||||
private val clientId = context.getString(R.string.anilist_clientId)
|
||||
private val clientSecret = context.getString(R.string.anilist_clientSecret)
|
||||
|
||||
override val oauthUrl: String
|
||||
get() = "${BASE_URL}oauth/authorize?client_id=${BuildConfig.ANILIST_CLIENT_ID}&" +
|
||||
get() = "${BASE_URL}oauth/authorize?client_id=$clientId&" +
|
||||
"redirect_uri=${REDIRECT_URI}&response_type=code"
|
||||
|
||||
override val isAuthorized: Boolean
|
||||
@@ -48,8 +55,8 @@ class AniListRepository(
|
||||
|
||||
override suspend fun authorize(code: String?) {
|
||||
val body = FormBody.Builder()
|
||||
body.add("client_id", BuildConfig.ANILIST_CLIENT_ID)
|
||||
body.add("client_secret", BuildConfig.ANILIST_CLIENT_SECRET)
|
||||
body.add("client_id", clientId)
|
||||
body.add("client_secret", clientSecret)
|
||||
if (code != null) {
|
||||
body.add("grant_type", "authorization_code")
|
||||
body.add("redirect_uri", REDIRECT_URI)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
package org.koitharu.kotatsu.scrobbling.mal.data
|
||||
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONNotNull
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblingEntity
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
|
||||
@@ -25,17 +28,19 @@ private const val BASE_API_URL = "https://api.myanimelist.net/v2"
|
||||
private const val AVATAR_STUB = "https://cdn.myanimelist.net/images/questionmark_50.gif"
|
||||
|
||||
class MALRepository(
|
||||
@ApplicationContext context: Context,
|
||||
private val okHttp: OkHttpClient,
|
||||
private val storage: ScrobblerStorage,
|
||||
private val db: MangaDatabase,
|
||||
) : org.koitharu.kotatsu.scrobbling.common.data.ScrobblerRepository {
|
||||
) : ScrobblerRepository {
|
||||
|
||||
private val clientId = context.getString(R.string.mal_clientId)
|
||||
private var codeVerifier: String = getPKCEChallengeCode()
|
||||
|
||||
override val oauthUrl: String
|
||||
get() = "$BASE_WEB_URL/v1/oauth2/authorize?" +
|
||||
"response_type=code" +
|
||||
"&client_id=${BuildConfig.MAL_CLIENT_ID}" +
|
||||
"&client_id=$clientId" +
|
||||
"&redirect_uri=$REDIRECT_URI" +
|
||||
"&code_challenge=$codeVerifier" +
|
||||
"&code_challenge_method=plain"
|
||||
@@ -51,7 +56,7 @@ class MALRepository(
|
||||
override suspend fun authorize(code: String?) {
|
||||
val body = FormBody.Builder()
|
||||
if (code != null) {
|
||||
body.add("client_id", BuildConfig.MAL_CLIENT_ID)
|
||||
body.add("client_id", clientId)
|
||||
body.add("grant_type", "authorization_code")
|
||||
body.add("code", code)
|
||||
body.add("redirect_uri", REDIRECT_URI)
|
||||
@@ -205,5 +210,4 @@ class MALRepository(
|
||||
avatar = json.getString("picture") ?: AVATAR_STUB,
|
||||
service = ScrobblerService.MAL,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.koitharu.kotatsu.scrobbling.shikimori.data
|
||||
|
||||
import android.content.Context
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
@@ -28,13 +30,17 @@ private const val BASE_URL = "https://shikimori.one/"
|
||||
private const val MANGA_PAGE_SIZE = 10
|
||||
|
||||
class ShikimoriRepository(
|
||||
@ApplicationContext context: Context,
|
||||
private val okHttp: OkHttpClient,
|
||||
private val storage: ScrobblerStorage,
|
||||
private val db: MangaDatabase,
|
||||
) : ScrobblerRepository {
|
||||
|
||||
private val clientId = context.getString(R.string.shikimori_clientId)
|
||||
private val clientSecret = context.getString(R.string.shikimori_clientSecret)
|
||||
|
||||
override val oauthUrl: String
|
||||
get() = "${BASE_URL}oauth/authorize?client_id=${BuildConfig.SHIKIMORI_CLIENT_ID}&" +
|
||||
get() = "${BASE_URL}oauth/authorize?client_id=$clientId&" +
|
||||
"redirect_uri=$REDIRECT_URI&response_type=code&scope="
|
||||
|
||||
override val isAuthorized: Boolean
|
||||
@@ -42,8 +48,8 @@ class ShikimoriRepository(
|
||||
|
||||
override suspend fun authorize(code: String?) {
|
||||
val body = FormBody.Builder()
|
||||
body.add("client_id", BuildConfig.SHIKIMORI_CLIENT_ID)
|
||||
body.add("client_secret", BuildConfig.SHIKIMORI_CLIENT_SECRET)
|
||||
body.add("client_id", clientId)
|
||||
body.add("client_secret", clientSecret)
|
||||
if (code != null) {
|
||||
body.add("grant_type", "authorization_code")
|
||||
body.add("redirect_uri", REDIRECT_URI)
|
||||
@@ -98,13 +104,13 @@ class ShikimoriRepository(
|
||||
return if (pageOffset != 0) list.drop(pageOffset) else list
|
||||
}
|
||||
|
||||
override suspend fun createRate(mangaId: Long, shikiMangaId: Long) {
|
||||
override suspend fun createRate(mangaId: Long, scrobblerMangaId: Long) {
|
||||
val user = cachedUser ?: loadUser()
|
||||
val payload = JSONObject()
|
||||
payload.put(
|
||||
"user_rate",
|
||||
JSONObject().apply {
|
||||
put("target_id", shikiMangaId)
|
||||
put("target_id", scrobblerMangaId)
|
||||
put("target_type", "Manga")
|
||||
put("user_id", user.id)
|
||||
},
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koitharu.kotatsu.R
|
||||
@@ -85,6 +86,10 @@ class ContentSettingsFragment :
|
||||
AppSettings.KEY_SOURCES_HIDDEN -> {
|
||||
bindRemoteSourcesSummary()
|
||||
}
|
||||
|
||||
AppSettings.KEY_SSL_BYPASS -> {
|
||||
Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.preference.PreferenceViewHolder
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.ColorScheme
|
||||
import org.koitharu.kotatsu.databinding.ItemColorSchemeBinding
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ThemeChooserPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
@@ -68,7 +69,7 @@ class ThemeChooserPreference @JvmOverloads constructor(
|
||||
}
|
||||
scrollView.viewTreeObserver.run {
|
||||
scrollPersistListener?.let { removeOnScrollChangedListener(it) }
|
||||
scrollPersistListener = ScrollPersistListener(scrollView, lastScrollPosition)
|
||||
scrollPersistListener = ScrollPersistListener(WeakReference(scrollView), lastScrollPosition)
|
||||
addOnScrollChangedListener(scrollPersistListener)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
@@ -106,7 +107,6 @@ class ThemeChooserPreference @JvmOverloads constructor(
|
||||
}
|
||||
super.onRestoreInstanceState(state.superState)
|
||||
lastScrollPosition[0] = state.scrollPosition
|
||||
// notifyChanged()
|
||||
}
|
||||
|
||||
private fun setValueInternal(enumName: String, notifyChanged: Boolean) {
|
||||
@@ -152,11 +152,12 @@ class ThemeChooserPreference @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private class ScrollPersistListener(
|
||||
private val scrollView: HorizontalScrollView,
|
||||
private val scrollViewRef: WeakReference<HorizontalScrollView>,
|
||||
private val lastScrollPosition: IntArray,
|
||||
) : ViewTreeObserver.OnScrollChangedListener {
|
||||
|
||||
override fun onScrollChanged() {
|
||||
val scrollView = scrollViewRef.get() ?: return
|
||||
lastScrollPosition[0] = scrollView.scrollX
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class SyncProvider : ContentProvider() {
|
||||
.selection(selection, selectionArgs)
|
||||
.orderBy(sortOrder)
|
||||
.create()
|
||||
logger.log("query: ${sqlQuery.sql}")
|
||||
logger.log("query: ${sqlQuery.sql} (${selectionArgs.contentToString()})")
|
||||
return database.openHelper.readableDatabase.query(sqlQuery)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ abstract class SyncProvider : ContentProvider() {
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
|
||||
val table = getTableName(uri) ?: return 0
|
||||
logger.log { "delete: $table ($selection) : ($selectionArgs)" }
|
||||
logger.log { "delete: $table ($selection) : (${selectionArgs.contentToString()})" }
|
||||
return database.openHelper.writableDatabase.delete(table, selection, selectionArgs)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ abstract class SyncProvider : ContentProvider() {
|
||||
if (values == null || table == null) {
|
||||
return 0
|
||||
}
|
||||
logger.log { "update: $table ($selection) : ($selectionArgs) [$values]" }
|
||||
logger.log { "update: $table ($selection) : (${selectionArgs.contentToString()}) [$values]" }
|
||||
return database.openHelper.writableDatabase
|
||||
.update(table, SQLiteDatabase.CONFLICT_IGNORE, values, selection, selectionArgs)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ package org.koitharu.kotatsu.utils.ext
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.IOException
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.util.parseJson
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
private val TYPE_JSON = "application/json".toMediaType()
|
||||
@@ -12,9 +13,13 @@ private val TYPE_JSON = "application/json".toMediaType()
|
||||
fun JSONObject.toRequestBody() = toString().toRequestBody(TYPE_JSON)
|
||||
|
||||
fun Response.parseJsonOrNull(): JSONObject? {
|
||||
return if (code == HttpURLConnection.HTTP_NO_CONTENT) {
|
||||
null
|
||||
} else {
|
||||
parseJson()
|
||||
return try {
|
||||
when {
|
||||
!isSuccessful -> throw IOException(body?.string())
|
||||
code == HttpURLConnection.HTTP_NO_CONTENT -> null
|
||||
else -> JSONObject(body?.string() ?: return null)
|
||||
}
|
||||
} finally {
|
||||
closeQuietly()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/name"
|
||||
android:imeOptions="actionDone"
|
||||
android:inputType="textCapSentences" />
|
||||
android:inputType="textCapSentences"
|
||||
android:maxLength="120" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
|
||||
@@ -403,7 +403,5 @@
|
||||
<string name="show_suspicious_content">Verdächtige Inhalte anzeigen</string>
|
||||
<string name="status_dropped">Abgebrochen</string>
|
||||
<string name="color_theme">Farbschema</string>
|
||||
<string name="theme_name_october">Oktober</string>
|
||||
<string name="theme_name_mint">Minze</string>
|
||||
<string name="theme_name_dynamic">Dynamisch</string>
|
||||
</resources>
|
||||
@@ -360,7 +360,6 @@
|
||||
<string name="explore">Explorar</string>
|
||||
<string name="memory_usage_pattern">%s - %s</string>
|
||||
<string name="changelog">Registro de cambios</string>
|
||||
<string name="tools">Herramientas</string>
|
||||
<string name="exit_confirmation_summary">Pulse dos veces «Atrás» para salir de la aplicación</string>
|
||||
<string name="exit_confirmation">Confirmación de salida</string>
|
||||
<string name="pages_cache">Caché de páginas</string>
|
||||
@@ -404,10 +403,8 @@
|
||||
<string name="enable_logging_summary">Grabar algunas acciones para depurar</string>
|
||||
<string name="enable_logging">Activar el registro</string>
|
||||
<string name="show_suspicious_content">Mostrar contenido sospechoso</string>
|
||||
<string name="theme_name_mint">Mint</string>
|
||||
<string name="theme_name_dynamic">Dinámico</string>
|
||||
<string name="color_theme">Esquema de colores</string>
|
||||
<string name="theme_name_october">Octubre</string>
|
||||
<string name="show_in_grid_view">Mostrar en vista de cuadrícula</string>
|
||||
<string name="theme_name_asuka">Asuka</string>
|
||||
<string name="theme_name_mion">Mion</string>
|
||||
@@ -422,4 +419,6 @@
|
||||
<string name="allow_unstable_updates_summary">Actualizaciones propuestas para las versiones beta de la aplicación</string>
|
||||
<string name="allow_unstable_updates">Permitir actualizaciones inestables</string>
|
||||
<string name="download_started">Descarga iniciada</string>
|
||||
<string name="user_agent">Encabezado del agente de usuario</string>
|
||||
<string name="settings_apply_restart_required">Por favor, reinicie la aplicación para aplicar estos cambios</string>
|
||||
</resources>
|
||||
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
@@ -403,10 +403,8 @@
|
||||
<string name="enable_logging_summary">Enregistrer certaines actions à des fins de débogage</string>
|
||||
<string name="language">Langue</string>
|
||||
<string name="show_suspicious_content">Afficher le contenu suspect</string>
|
||||
<string name="theme_name_mint">Menthe</string>
|
||||
<string name="theme_name_dynamic">Dynamique</string>
|
||||
<string name="color_theme">Schéma de couleurs</string>
|
||||
<string name="theme_name_october">Octobre</string>
|
||||
<string name="show_in_grid_view">Afficher en vue grille</string>
|
||||
<string name="scrobbling_empty_hint">Pour suivre la progression de la lecture, sélectionnez Menu → Suivre sur l\'écran des détails du manga.</string>
|
||||
<string name="services">Prestations de service</string>
|
||||
@@ -421,4 +419,5 @@
|
||||
<string name="download_started">Téléchargement commencé</string>
|
||||
<string name="theme_name_kanade">Kanade</string>
|
||||
<string name="allow_unstable_updates_summary">Proposer des mises à jour des versions bêta de l\'application</string>
|
||||
<string name="user_agent">En-tête UserAgent</string>
|
||||
</resources>
|
||||
@@ -403,8 +403,6 @@
|
||||
<string name="enable_logging_summary">Registra alcune azioni a scopo di debug</string>
|
||||
<string name="enable_logging">Abilita la registrazione</string>
|
||||
<string name="show_suspicious_content">Mostra il contenuto sospetto</string>
|
||||
<string name="theme_name_mint">Menta</string>
|
||||
<string name="theme_name_october">Ottobre</string>
|
||||
<string name="theme_name_dynamic">Dinamico</string>
|
||||
<string name="color_theme">Schema colori</string>
|
||||
<string name="show_in_grid_view">Mostra nella vista griglia</string>
|
||||
|
||||
@@ -327,7 +327,6 @@
|
||||
<string name="empty">空</string>
|
||||
<string name="changelog">変更ログ</string>
|
||||
<string name="explore">探検</string>
|
||||
<string name="tools">ツール</string>
|
||||
<string name="exit_confirmation_summary">アプリを終了するには、戻るを2回押してください</string>
|
||||
<string name="saved_manga">保存したマンガ</string>
|
||||
<string name="app_update_available_s">アプリケーションのアップデートが利用可能: %s</string>
|
||||
|
||||
@@ -341,7 +341,6 @@
|
||||
<string name="exit_confirmation">Avsluttingsbekreftelse</string>
|
||||
<string name="invalid_domain_message">Ugyldig daomene</string>
|
||||
<string name="share_logs">Del loggføring</string>
|
||||
<string name="theme_name_october">Oktober</string>
|
||||
<string name="color_theme">Fargedrakt</string>
|
||||
<string name="theme_name_dynamic">Dynamisk</string>
|
||||
<string name="language">Språk</string>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<string name="favourites">Favoritos</string>
|
||||
<string name="history">Histórico</string>
|
||||
<string name="error_occurred">Um erro ocorreu</string>
|
||||
<string name="network_error">Não foi possível conectar à Internet</string>
|
||||
<string name="network_error">Erro de rede</string>
|
||||
<string name="details">Detalhes</string>
|
||||
<string name="chapters">Capítulos</string>
|
||||
<string name="list">Lista</string>
|
||||
@@ -385,4 +385,29 @@
|
||||
<string name="text_unsaved_changes_prompt">Você tem alterações não salvas, deseja salvá-las ou descartá-las\?</string>
|
||||
<string name="discard">Descartar</string>
|
||||
<string name="not_found_404">Conteúdo não encontrado ou removido</string>
|
||||
<string name="services">Serviços</string>
|
||||
<string name="nothing_here">Não há nada aqui</string>
|
||||
<string name="server_error">Erro do lado do servidor (%1$d). Por favor, tente novamente mais tarde</string>
|
||||
<string name="compact">Compactar</string>
|
||||
<string name="enable_logging">Habilitar registros</string>
|
||||
<string name="share_logs">Compartilhar registros</string>
|
||||
<string name="error_no_space_left">Não há espaço disponível no aparelho</string>
|
||||
<string name="network_unavailable">A rede não está disponível</string>
|
||||
<string name="network_unavailable_hint">Ative o Wi-Fi ou a rede móvel para ler mangá online</string>
|
||||
<string name="allow_unstable_updates">Permitir atualizações instáveis</string>
|
||||
<string name="download_started">Download iniciado</string>
|
||||
<string name="language">Idioma</string>
|
||||
<string name="mark_as_current">Marcar como atual</string>
|
||||
<string name="show_in_grid_view">Mostrar na visualização em grade</string>
|
||||
<string name="color_theme">Esquema de cores</string>
|
||||
<string name="show_suspicious_content">Exibir conteúdo suspeito</string>
|
||||
<string name="prefetch_content">Pré-carregamento de conteúdo</string>
|
||||
<string name="theme_name_dynamic">Dinâmico</string>
|
||||
<string name="settings_apply_restart_required">Por favor, reinicie o app para aplicar essas mudanças</string>
|
||||
<string name="different_languages">Idiomas diferentes</string>
|
||||
<string name="theme_name_asuka">Asuka</string>
|
||||
<string name="theme_name_mion">Mion</string>
|
||||
<string name="theme_name_rikka">Rikka</string>
|
||||
<string name="theme_name_sakura">Sakura</string>
|
||||
<string name="source_disabled">Fonte desativada</string>
|
||||
</resources>
|
||||
@@ -396,4 +396,5 @@
|
||||
<string name="reader_control_ltr">Controle de leitura ergonômico</string>
|
||||
<string name="color_correction_hint">As configurações de cor escolhidas serão lembradas para esse mangá</string>
|
||||
<string name="discard">Descartar</string>
|
||||
<string name="language">Idioma</string>
|
||||
</resources>
|
||||
@@ -331,7 +331,6 @@
|
||||
<string name="reorder">Упорядочить</string>
|
||||
<string name="empty">Пусто</string>
|
||||
<string name="explore">Обзор</string>
|
||||
<string name="tools">Инструменты</string>
|
||||
<string name="confirm_exit">Нажмите Назад ещё раз, чтобы выйти</string>
|
||||
<string name="exit_confirmation_summary">Нажмите Назад 2 раза для выхода из приложения</string>
|
||||
<string name="other_cache">Другой кэш</string>
|
||||
@@ -404,10 +403,8 @@
|
||||
<string name="enable_logging">Включить логирование</string>
|
||||
<string name="enable_logging_summary">Записывать некоторые действия для отладки</string>
|
||||
<string name="show_suspicious_content">Отображать сомнительный контент</string>
|
||||
<string name="theme_name_mint">Мята</string>
|
||||
<string name="theme_name_dynamic">Динамическая</string>
|
||||
<string name="color_theme">Цветовая схема</string>
|
||||
<string name="theme_name_october">Октябрь</string>
|
||||
<string name="show_in_grid_view">Показать в виде сетки</string>
|
||||
<string name="theme_name_miku">Мику</string>
|
||||
<string name="theme_name_asuka">Аска</string>
|
||||
@@ -422,4 +419,6 @@
|
||||
<string name="download_started">Загрузка началась</string>
|
||||
<string name="allow_unstable_updates">Разрешить нестабильные обновления</string>
|
||||
<string name="allow_unstable_updates_summary">Предлагать обновления до бета-версий приложения</string>
|
||||
<string name="settings_apply_restart_required">Пожалуйста, перезапустите приложение, чтобы применить эти изменения</string>
|
||||
<string name="user_agent">Заголовок UserAgent</string>
|
||||
</resources>
|
||||
@@ -409,4 +409,16 @@
|
||||
<string name="theme_name_dynamic">Dinamik</string>
|
||||
<string name="color_theme">renk vurgusu</string>
|
||||
<string name="show_in_grid_view">Izgara görünümünde göster</string>
|
||||
<string name="theme_name_mamimi">Mamimi</string>
|
||||
<string name="theme_name_kanade">Kanade</string>
|
||||
<string name="user_agent">UserAgent başlığı</string>
|
||||
<string name="allow_unstable_updates_summary">Uygulamanın beta sürümleri için güncellemeler öner</string>
|
||||
<string name="allow_unstable_updates">Kararsız güncellemelere izin ver</string>
|
||||
<string name="download_started">İndirme başladı</string>
|
||||
<string name="theme_name_miku">Miku</string>
|
||||
<string name="theme_name_asuka">Asuka</string>
|
||||
<string name="theme_name_mion">Mion</string>
|
||||
<string name="theme_name_rikka">Rikka</string>
|
||||
<string name="theme_name_sakura">Sakura</string>
|
||||
<string name="settings_apply_restart_required">Bu değişiklikleri uygulamak için lütfen uygulamayı yeniden başlatın</string>
|
||||
</resources>
|
||||
@@ -416,4 +416,7 @@
|
||||
<string name="theme_name_dynamic">Динамічний</string>
|
||||
<string name="color_theme">Колірний акцент</string>
|
||||
<string name="show_in_grid_view">Показати у вигляді сітки</string>
|
||||
<string name="allow_unstable_updates">Дозволити нестабільні оновлення</string>
|
||||
<string name="allow_unstable_updates_summary">Пропонувати оновлення до бета-версій додатку</string>
|
||||
<string name="download_started">Завантаження розпочато</string>
|
||||
</resources>
|
||||
@@ -421,4 +421,6 @@
|
||||
<string name="allow_unstable_updates">允许不稳定更新</string>
|
||||
<string name="allow_unstable_updates_summary">提示更新到测试版</string>
|
||||
<string name="download_started">已开始下载</string>
|
||||
<string name="user_agent">UserAgent 标头</string>
|
||||
<string name="settings_apply_restart_required">要应用这些更改请重启程序</string>
|
||||
</resources>
|
||||
@@ -9,6 +9,13 @@
|
||||
<string name="url_error_report" translatable="false">https://acra.rumblur.space/report</string>
|
||||
<string name="account_type_sync" translatable="false">org.kotatsu.sync</string>
|
||||
<string name="url_sync_server" translatable="false">http://86.57.183.214:8081</string>
|
||||
<string name="shikimori_clientId" translatable="false">Mw6F0tPEOgyV7F9U9Twg50Q8SndMY7hzIOfXg0AX_XU</string>
|
||||
<string name="shikimori_clientSecret" translatable="false">euBMt1GGRSDpVIFQVPxZrO7Kh6X4gWyv0dABuj4B-M8</string>
|
||||
<string name="anilist_clientId" translatable="false">9887</string>
|
||||
<string name="anilist_clientSecret" translatable="false">wrMqFosItQWsmB8dtAHfIFPDt15FfQi2ZGiKkJoW</string>
|
||||
<string name="mal_clientId" translatable="false">6cd8e6349e9a36bc1fc1ab97703c9fd1</string>
|
||||
<string name="acra_login" translatable="false">SxhkCVnqVLbGogvi</string>
|
||||
<string name="acra_password" translatable="false">xPDACTLHnHU9Nfjv</string>
|
||||
<string-array name="values_theme" translatable="false">
|
||||
<item>-1</item>
|
||||
<item>1</item>
|
||||
|
||||
@@ -425,4 +425,5 @@
|
||||
<string name="allow_unstable_updates_summary">Propose updates to beta versions of the app</string>
|
||||
<string name="download_started">Download started</string>
|
||||
<string name="user_agent">UserAgent header</string>
|
||||
<string name="settings_apply_restart_required">Please restart the application to apply these changes</string>
|
||||
</resources>
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
android:title="@string/suggestions"
|
||||
app:allowDividerAbove="true" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/doh_providers"
|
||||
android:key="doh"
|
||||
android:title="@string/dns_over_https"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="0"
|
||||
android:entries="@array/network_policy"
|
||||
@@ -56,6 +50,17 @@
|
||||
android:valueTo="5"
|
||||
app:defaultValue="2" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/doh_providers"
|
||||
android:key="doh"
|
||||
android:title="@string/dns_over_https"
|
||||
app:allowDividerAbove="true"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="ssl_bypass"
|
||||
android:title="Ignore SSL errors" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.koitharu.kotatsu.settings.backup.BackupSettingsFragment"
|
||||
android:title="@string/backup_restore"
|
||||
|
||||
11
build.gradle
11
build.gradle
@@ -4,7 +4,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
|
||||
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.45'
|
||||
}
|
||||
@@ -20,15 +20,6 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
String localProperty(String name, String defaultValue = 'null') {
|
||||
Properties localProperties = new Properties()
|
||||
project.rootProject.file('local.properties').withInputStream { localProperties.load(it) }
|
||||
|
||||
def value = localProperties[name]
|
||||
|
||||
return value != null ? value : defaultValue
|
||||
}
|
||||
|
||||
String currentBranch() {
|
||||
def branchName = ""
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user