Compare commits

..

5 Commits

Author SHA1 Message Date
Koitharu
0153e90bf0 Fix build 2025-01-22 20:35:51 +02:00
Koitharu
d4f8fe83f5 Release signing config 2025-01-22 20:27:30 +02:00
Koitharu
d28b1e4094 Release build workflow 2025-01-22 20:22:03 +02:00
Koitharu
cd2de0136a Support for dynamic version 2025-01-22 20:22:02 +02:00
Koitharu
15e99c03a9 Update parsers and adjust imports
(cherry picked from commit 5e8aa4cec7)
2025-01-22 20:21:43 +02:00
45 changed files with 255 additions and 134 deletions

114
.github/workflows/auto_release.yml vendored Normal file
View File

@@ -0,0 +1,114 @@
name: Build automatic release
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-24.04
outputs:
should_build: ${{ steps.check-updates.outputs.has_changes }}
steps:
- name: Check for updates 🌏
id: check-updates
run: |
last_run=$(curl -s "https://api.github.com/repos/${{ github.repository }}/releases/latest" | jq -r '.created_at')
kotatsu_updated=$(curl -s "https://api.github.com/repos/KotatsuApp/Kotatsu/commits?since=$last_run" | jq '. | length')
parsers_updated=$(curl -s "https://api.github.com/repos/KotatsuApp/kotatsu-parsers/commits?since=$last_run" | jq '. | length')
if [ "$kotatsu_updated" -gt "0" ] || [ "$parsers_updated" -gt "0" ]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi
build:
needs: check
if: needs.check.outputs.should_build == 'true'
runs-on: ubuntu-24.04
outputs:
new_tag: ${{ steps.tagger.outputs.new_tag }}
steps:
- uses: actions/checkout@v3
with:
ref: autobuild
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
cache: 'gradle'
- name: Setup Android SDK 💻
uses: android-actions/setup-android@v3
- name: Grant permissions 💻
run: chmod a+x gradlew
- name: Generate build number 📆
id: tagger
run: |
echo "new_tag=$(./gradlew -q versionInfo -DbuildNumberIncrement=true)" >> $GITHUB_OUTPUT
echo "formatted_date=$(date +'%Y/%m/%d')" >> $GITHUB_OUTPUT
- name: Decode Keystore
id: decode_keystore
uses: timheuer/base64-to-file@v1
with:
fileName: 'keystore/kotatsu.jks'
encodedString: ${{ secrets.ANDROID_SIGNING_KEY }}
- name: Building new APK 💻
run: >-
./gradlew assembleRelease
-DparsersVersionOverride=$(curl -s https://api.github.com/repos/kotatsuapp/kotatsu-parsers/commits/master -H "Accept: application/vnd.github.sha" | cut -c -10)
- name: Prepare to Upload 🌏
run: |
mv ${{steps.sign_app.outputs.signedFile}} app/build/outputs/apk/release/release.apk
echo "SIGNED_APK=app/build/outputs/apk/release/release.apk" >> $GITHUB_ENV
- name: Get latest changes 📑
id: changelog
run: |
CHANGELOG=$(cat CHANGELOG.txt)
echo "content<<EOF" >> $GITHUB_OUTPUT
echo "$CHANGELOG" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create new GH Release + Uploading 🌏
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.tagger.outputs.new_tag }}
name: "Build ${{ steps.tagger.outputs.new_tag }}"
body: |
Automated build generated on ${{ steps.tagger.outputs.formatted_date }}
${{ steps.changelog.outputs.content }}
files: ${{ env.SIGNED_APK }}
prerelease: false
update:
needs: build
if: needs.check.outputs.should_build == 'true'
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
ref: autobuild
fetch-depth: 0
- name: Commit 🌏
run: |
git config --local user.email "autorelease@users.noreply.github.com"
git config --local user.name "autorelease"
if [[ -n $(git status -s) ]]; then
git add README.md
git commit -m "Automatic release v${{ needs.build.outputs.new_tag }}"
git push origin autobuild
else
echo "No changes to push!"
fi

View File

@@ -9,17 +9,24 @@ plugins {
id 'dagger.hilt.android.plugin' id 'dagger.hilt.android.plugin'
} }
def Properties versionProps = getVersionProps()
android { android {
compileSdk = 35 compileSdk = 35
buildToolsVersion = '35.0.0' buildToolsVersion = '35.0.0'
namespace = 'org.koitharu.kotatsu' namespace = 'org.koitharu.kotatsu'
defaultConfig { defaultConfig {
def code = versionProps['code'].toInteger()
def base = versionProps['base'].trim()
def build = versionProps['build'].toInteger()
def variant = versionProps['variant'].trim()
applicationId 'org.koitharu.kotatsu' applicationId 'org.koitharu.kotatsu'
minSdk = 21 minSdk = 21
targetSdk = 35 targetSdk = 35
versionCode = 700 versionCode = code * 1000 + build
versionName = '7.7.8' versionName = base + (build == 0 ? '' : '.' + build) + (variant == '' ? '' : '-') + variant
generatedDensities = [] generatedDensities = []
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
ksp { ksp {
@@ -30,6 +37,22 @@ android {
generateLocaleConfig true generateLocaleConfig true
} }
} }
signingConfigs {
release {
def tmpFilePath = System.getProperty("user.home") + "/work/_temp/keystore/"
def allFilesFromDir = new File(tmpFilePath).listFiles()
if (allFilesFromDir != null) {
def keystoreFile = allFilesFromDir.first()
keystoreFile.renameTo("keystore/kotatsu.jks")
}
storeFile = file("keystore/kotatsu.jks")
storePassword System.getenv("SIGNING_STORE_PASSWORD")
keyAlias System.getenv("SIGNING_KEY_ALIAS")
keyPassword System.getenv("SIGNING_KEY_PASSWORD")
}
}
buildTypes { buildTypes {
debug { debug {
applicationIdSuffix = '.debug' applicationIdSuffix = '.debug'
@@ -38,6 +61,7 @@ android {
minifyEnabled true minifyEnabled true
shrinkResources true shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
} }
nightly { nightly {
initWith release initWith release
@@ -194,3 +218,22 @@ dependencies {
androidTestImplementation libs.hilt.android.testing androidTestImplementation libs.hilt.android.testing
kaptAndroidTest libs.hilt.android.compiler kaptAndroidTest libs.hilt.android.compiler
} }
tasks.register('versionInfo') {
def base = versionProps['base'].trim()
def build = versionProps['build'].toInteger()
def variant = versionProps['variant'].trim()
println base + (build == 0 ? '' : '.' + build) + (variant == '' ? '' : '-') + variant
}
def getVersionProps() {
def versionPropsFile = file('version.properties')
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
if (System.getProperty('buildNumberIncrement') == 'true') {
def code = versionProps['build'].toInteger() + 1
versionProps['build'] = code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
}
return versionProps
}

View File

@@ -8,13 +8,13 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit import kotlinx.coroutines.sync.withPermit
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.almostEquals
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import javax.inject.Inject import javax.inject.Inject

View File

@@ -1,11 +1,11 @@
package org.koitharu.kotatsu.core.db.entity package org.koitharu.kotatsu.core.db.entity
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.util.ext.longHashCode
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaState import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.longHashCode
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.toTitleCase import org.koitharu.kotatsu.parsers.util.toTitleCase

View File

@@ -1,6 +1,6 @@
package org.koitharu.kotatsu.core.github package org.koitharu.kotatsu.core.github
import org.koitharu.kotatsu.core.util.ext.digits import org.koitharu.kotatsu.parsers.util.digits
import java.util.Locale import java.util.Locale
data class VersionId( data class VersionId(

View File

@@ -5,7 +5,7 @@ import androidx.annotation.WorkerThread
import androidx.core.util.Predicate import androidx.core.util.Predicate
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.HttpUrl import okhttp3.HttpUrl
import org.koitharu.kotatsu.core.util.ext.newBuilder import org.koitharu.kotatsu.parsers.util.newBuilder
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine

View File

@@ -17,8 +17,8 @@ import org.jsoup.HttpStatusException
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.exceptions.CloudFlareBlockedException import org.koitharu.kotatsu.core.exceptions.CloudFlareBlockedException
import org.koitharu.kotatsu.core.util.ext.ensureSuccess import org.koitharu.kotatsu.core.util.ext.ensureSuccess
import org.koitharu.kotatsu.core.util.ext.isHttpOrHttps
import org.koitharu.kotatsu.parsers.util.await import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.parsers.util.isHttpOrHttps
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.util.Collections import java.util.Collections

View File

@@ -6,13 +6,13 @@ import dagger.Reusable
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.UnknownMangaSource import org.koitharu.kotatsu.core.model.UnknownMangaSource
import org.koitharu.kotatsu.core.model.isNsfw import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.MangaLoaderContext import org.koitharu.kotatsu.parsers.MangaLoaderContext
import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.almostEquals import org.koitharu.kotatsu.parsers.util.almostEquals
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.levenshteinDistance import org.koitharu.kotatsu.parsers.util.levenshteinDistance
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import javax.inject.Inject import javax.inject.Inject

View File

@@ -7,8 +7,6 @@ import androidx.collection.ArraySet
import androidx.core.net.toUri import androidx.core.net.toUri
import org.jetbrains.annotations.Blocking import org.jetbrains.annotations.Blocking
import org.koitharu.kotatsu.core.exceptions.IncompatiblePluginException import org.koitharu.kotatsu.core.exceptions.IncompatiblePluginException
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.ContentRating import org.koitharu.kotatsu.parsers.model.ContentRating
import org.koitharu.kotatsu.parsers.model.ContentType import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.Demographic import org.koitharu.kotatsu.parsers.model.Demographic
@@ -22,6 +20,7 @@ import org.koitharu.kotatsu.parsers.model.MangaState
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.find import org.koitharu.kotatsu.parsers.util.find
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
import org.koitharu.kotatsu.parsers.util.splitTwoParts import org.koitharu.kotatsu.parsers.util.splitTwoParts
import java.util.EnumSet import java.util.EnumSet

View File

@@ -4,13 +4,13 @@ import android.content.Context
import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.core.content.edit import androidx.core.content.edit
import org.koitharu.kotatsu.core.util.ext.getEnumValue import org.koitharu.kotatsu.core.util.ext.getEnumValue
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.putEnumValue import org.koitharu.kotatsu.core.util.ext.putEnumValue
import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue import org.koitharu.kotatsu.core.util.ext.sanitizeHeaderValue
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.nullIfEmpty import org.koitharu.kotatsu.parsers.util.nullIfEmpty
import org.koitharu.kotatsu.settings.utils.validation.DomainValidator import org.koitharu.kotatsu.settings.utils.validation.DomainValidator

View File

@@ -4,21 +4,8 @@ import androidx.collection.ArrayMap
import androidx.collection.ArraySet import androidx.collection.ArraySet
import androidx.collection.LongSet import androidx.collection.LongSet
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import java.util.Collections
import java.util.EnumSet import java.util.EnumSet
inline fun <T> MutableSet(size: Int, init: (index: Int) -> T): MutableSet<T> {
val set = ArraySet<T>(size)
repeat(size) { index -> set.add(init(index)) }
return set
}
inline fun <T> Set(size: Int, init: (index: Int) -> T): Set<T> = when (size) {
0 -> emptySet()
1 -> Collections.singleton(init(0))
else -> MutableSet(size, init)
}
fun <T> Collection<T>.asArrayList(): ArrayList<T> = if (this is ArrayList<*>) { fun <T> Collection<T>.asArrayList(): ArrayList<T> = if (this is ArrayList<*>) {
this as ArrayList<T> this as ArrayList<T>
} else { } else {
@@ -76,15 +63,6 @@ fun <T> Iterable<T>.sortedWithSafe(comparator: Comparator<in T>): List<T> = try
} }
} }
fun Collection<*>?.sizeOrZero() = this?.size ?: 0
@Suppress("UNCHECKED_CAST")
inline fun <T, reified R> Collection<T>.mapToArray(transform: (T) -> R): Array<R> {
val result = arrayOfNulls<R>(size)
forEachIndexed { index, t -> result[index] = transform(t) }
return result as Array<R>
}
fun LongSet.toLongArray(): LongArray { fun LongSet.toLongArray(): LongArray {
val result = LongArray(size) val result = LongArray(size)
var i = 0 var i = 0

View File

@@ -1,7 +1,5 @@
package org.koitharu.kotatsu.core.util.ext package org.koitharu.kotatsu.core.util.ext
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
@@ -27,12 +25,6 @@ fun Response.parseJsonOrNull(): JSONObject? {
} }
} }
val HttpUrl.isHttpOrHttps: Boolean
get() {
val s = scheme.lowercase()
return s == "https" || s == "http"
}
fun Response.ensureSuccess() = apply { fun Response.ensureSuccess() = apply {
if (!isSuccessful || code == HttpURLConnection.HTTP_NO_CONTENT) { if (!isSuccessful || code == HttpURLConnection.HTTP_NO_CONTENT) {
closeQuietly() closeQuietly()
@@ -40,26 +32,6 @@ fun Response.ensureSuccess() = apply {
} }
} }
fun Cookie.newBuilder(): Cookie.Builder = Cookie.Builder().also { c ->
c.name(name)
c.value(value)
if (persistent) {
c.expiresAt(expiresAt)
}
if (hostOnly) {
c.hostOnlyDomain(domain)
} else {
c.domain(domain)
}
c.path(path)
if (secure) {
c.secure()
}
if (httpOnly) {
c.httpOnly()
}
}
fun String.sanitizeHeaderValue(): String { fun String.sanitizeHeaderValue(): String {
return if (all(Char::isValidForHeaderValue)) { return if (all(Char::isValidForHeaderValue)) {
this // fast path this // fast path

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.core.util.ext
import android.content.Context import android.content.Context
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.parsers.util.Set
import org.koitharu.kotatsu.parsers.util.toTitleCase import org.koitharu.kotatsu.parsers.util.toTitleCase
import java.util.Locale import java.util.Locale

View File

@@ -1,7 +1,2 @@
package org.koitharu.kotatsu.core.util.ext package org.koitharu.kotatsu.core.util.ext
inline fun Long.ifZero(defaultValue: () -> Long): Long = if (this == 0L) defaultValue() else this
fun longOf(a: Int, b: Int): Long {
return a.toLong() shl 32 or (b.toLong() and 0xffffffffL)
}

View File

@@ -2,25 +2,11 @@ package org.koitharu.kotatsu.core.util.ext
import android.content.Context import android.content.Context
import android.database.DatabaseUtils import android.database.DatabaseUtils
import androidx.annotation.FloatRange import androidx.collection.arraySetOf
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.parsers.util.ellipsize import org.koitharu.kotatsu.parsers.util.ellipsize
import org.koitharu.kotatsu.parsers.util.levenshteinDistance
import java.util.UUID import java.util.UUID
inline fun <C : R, R : CharSequence?> C?.ifNullOrEmpty(defaultValue: () -> R): R {
return if (this.isNullOrEmpty()) defaultValue() else this
}
fun String.longHashCode(): Long {
var h = 1125899906842597L
val len: Int = this.length
for (i in 0 until len) {
h = 31 * h + this[i].code
}
return h
}
fun String.toUUIDOrNull(): UUID? = try { fun String.toUUIDOrNull(): UUID? = try {
UUID.fromString(this) UUID.fromString(this)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
@@ -28,19 +14,35 @@ fun String.toUUIDOrNull(): UUID? = try {
null null
} }
fun String.digits() = filter { it.isDigit() } fun String.transliterate(skipMissing: Boolean): String {
val cyr = charArrayOf(
/** 'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п',
* @param threshold 0 = exact match 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я', 'ё', 'ў',
*/ )
fun String.almostEquals(other: String, @FloatRange(from = 0.0) threshold: Float): Boolean { val lat = arrayOf(
if (threshold == 0f) { "a", "b", "v", "g", "d", "e", "zh", "z", "i", "y", "k", "l", "m", "n", "o", "p",
return equals(other, ignoreCase = true) "r", "s", "t", "u", "f", "h", "ts", "ch", "sh", "sch", "", "i", "", "e", "ju", "ja", "jo", "w",
)
return buildString(length + 5) {
for (c in this@transliterate) {
val p = cyr.binarySearch(c.lowercaseChar())
if (p in lat.indices) {
if (c.isUpperCase()) {
append(lat[p].uppercase())
} else {
append(lat[p])
}
} else if (!skipMissing) {
append(c)
}
}
} }
val diff = lowercase().levenshteinDistance(other.lowercase()) / ((length + other.length) / 2f)
return diff < threshold
} }
fun String.toFileNameSafe(): String = this.transliterate(false)
.replace(Regex("[^a-z0-9_\\-]", arraySetOf(RegexOption.IGNORE_CASE)), " ")
.replace(Regex("\\s+"), "_")
fun CharSequence.sanitize(): CharSequence { fun CharSequence.sanitize(): CharSequence {
return filterNot { c -> c.isReplacement() } return filterNot { c -> c.isReplacement() }
} }
@@ -68,10 +70,11 @@ fun <T> Collection<T>.joinToStringWithLimit(context: Context, limit: Int, transf
} }
} }
@Deprecated("", @Deprecated(
"",
ReplaceWith( ReplaceWith(
"sqlEscapeString(this)", "sqlEscapeString(this)",
"android.database.DatabaseUtils.sqlEscapeString" "android.database.DatabaseUtils.sqlEscapeString",
) ),
) )
fun String.sqlEscape(): String = DatabaseUtils.sqlEscapeString(this) fun String.sqlEscape(): String = DatabaseUtils.sqlEscapeString(this)

View File

@@ -38,6 +38,7 @@ import org.koitharu.kotatsu.parsers.exception.ContentUnavailableException
import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.ParseException
import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.scrobbling.common.domain.ScrobblerAuthRequiredException import org.koitharu.kotatsu.scrobbling.common.domain.ScrobblerAuthRequiredException
import java.io.ObjectOutputStream import java.io.ObjectOutputStream
import java.net.ConnectException import java.net.ConnectException

View File

@@ -77,7 +77,6 @@ import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
import org.koitharu.kotatsu.core.util.ext.drawable import org.koitharu.kotatsu.core.util.ext.drawable
import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.core.util.ext.getThemeColor
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.isTextTruncated import org.koitharu.kotatsu.core.util.ext.isTextTruncated
import org.koitharu.kotatsu.core.util.ext.joinToStringWithLimit import org.koitharu.kotatsu.core.util.ext.joinToStringWithLimit
import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra
@@ -113,6 +112,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.ellipsize import org.koitharu.kotatsu.parsers.util.ellipsize
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet

View File

@@ -27,7 +27,6 @@ import org.koitharu.kotatsu.core.ui.widgets.TwoLinesItemView
import org.koitharu.kotatsu.core.util.ext.findActivity import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.joinToStringWithLimit import org.koitharu.kotatsu.core.util.ext.joinToStringWithLimit
import org.koitharu.kotatsu.core.util.ext.mapToArray
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.parentView import org.koitharu.kotatsu.core.util.ext.parentView
@@ -39,6 +38,7 @@ import org.koitharu.kotatsu.download.ui.list.DownloadsActivity
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.format import org.koitharu.kotatsu.parsers.util.format
import org.koitharu.kotatsu.parsers.util.mapToArray
import org.koitharu.kotatsu.settings.storage.DirectoryModel import org.koitharu.kotatsu.settings.storage.DirectoryModel
import javax.inject.Inject import javax.inject.Inject

View File

@@ -21,7 +21,6 @@ import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.require import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
import org.koitharu.kotatsu.download.ui.worker.DownloadTask import org.koitharu.kotatsu.download.ui.worker.DownloadTask
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.history.data.HistoryRepository
@@ -30,6 +29,7 @@ import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.sizeOrZero
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import org.koitharu.kotatsu.settings.storage.DirectoryModel import org.koitharu.kotatsu.settings.storage.DirectoryModel
import javax.inject.Inject import javax.inject.Inject

View File

@@ -60,7 +60,6 @@ import org.koitharu.kotatsu.core.util.ext.ensureSuccess
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.getWorkInputData import org.koitharu.kotatsu.core.util.ext.getWorkInputData
import org.koitharu.kotatsu.core.util.ext.getWorkSpec import org.koitharu.kotatsu.core.util.ext.getWorkSpec
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.withTicker import org.koitharu.kotatsu.core.util.ext.withTicker
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
@@ -79,6 +78,7 @@ import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.requireBody import org.koitharu.kotatsu.parsers.util.requireBody
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable

View File

@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.explore.domain
import org.koitharu.kotatsu.core.model.isNsfw import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.core.util.ext.asArrayList import org.koitharu.kotatsu.core.util.ext.asArrayList
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
@@ -11,6 +10,7 @@ import org.koitharu.kotatsu.history.data.HistoryRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.almostEquals
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.suggestions.domain.TagsBlacklist import org.koitharu.kotatsu.suggestions.domain.TagsBlacklist
import javax.inject.Inject import javax.inject.Inject
@@ -77,7 +77,7 @@ class ExploreRepository @Inject constructor(
val list = repository.getList( val list = repository.getList(
offset = 0, offset = 0,
order = order, order = order,
filter = MangaListFilter(tags = setOfNotNull(tag)) filter = MangaListFilter(tags = setOfNotNull(tag)),
).asArrayList() ).asArrayList()
if (settings.isSuggestionsExcludeNsfw) { if (settings.isSuggestionsExcludeNsfw) {
list.removeAll { it.isNsfw } list.removeAll { it.isNsfw }

View File

@@ -1,8 +1,8 @@
package org.koitharu.kotatsu.explore.ui.model package org.koitharu.kotatsu.explore.ui.model
import org.koitharu.kotatsu.core.model.MangaSourceInfo import org.koitharu.kotatsu.core.model.MangaSourceInfo
import org.koitharu.kotatsu.core.util.ext.longHashCode
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.util.longHashCode
data class MangaSourceItem( data class MangaSourceItem(
val source: MangaSourceInfo, val source: MangaSourceInfo,

View File

@@ -28,7 +28,6 @@ import org.koitharu.kotatsu.core.util.ext.crossfade
import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders import org.koitharu.kotatsu.core.util.ext.defaultPlaceholders
import org.koitharu.kotatsu.core.util.ext.drawable import org.koitharu.kotatsu.core.util.ext.drawable
import org.koitharu.kotatsu.core.util.ext.enqueueWith import org.koitharu.kotatsu.core.util.ext.enqueueWith
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
@@ -40,6 +39,7 @@ import org.koitharu.kotatsu.image.ui.ImageActivity
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaListFilter import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.reader.ui.ReaderActivity import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.search.ui.MangaListActivity
import javax.inject.Inject import javax.inject.Inject

View File

@@ -16,13 +16,12 @@ import okio.use
import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException
import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.FileSize
import org.koitharu.kotatsu.core.util.ext.compressToPNG import org.koitharu.kotatsu.core.util.ext.compressToPNG
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.subdir import org.koitharu.kotatsu.core.util.ext.subdir
import org.koitharu.kotatsu.core.util.ext.takeIfReadable import org.koitharu.kotatsu.core.util.ext.takeIfReadable
import org.koitharu.kotatsu.core.util.ext.takeIfWriteable import org.koitharu.kotatsu.core.util.ext.takeIfWriteable
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import java.io.File import java.io.File

View File

@@ -22,8 +22,8 @@ import org.koitharu.kotatsu.core.util.ext.URI_SCHEME_ZIP
import org.koitharu.kotatsu.core.util.ext.isFileUri import org.koitharu.kotatsu.core.util.ext.isFileUri
import org.koitharu.kotatsu.core.util.ext.isRegularFile import org.koitharu.kotatsu.core.util.ext.isRegularFile
import org.koitharu.kotatsu.core.util.ext.isZipUri import org.koitharu.kotatsu.core.util.ext.isZipUri
import org.koitharu.kotatsu.core.util.ext.longHashCode
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.toFileNameSafe
import org.koitharu.kotatsu.core.util.ext.toListSorted import org.koitharu.kotatsu.core.util.ext.toListSorted
import org.koitharu.kotatsu.local.data.MangaIndex import org.koitharu.kotatsu.local.data.MangaIndex
import org.koitharu.kotatsu.local.data.hasZipExtension import org.koitharu.kotatsu.local.data.hasZipExtension
@@ -33,8 +33,8 @@ import org.koitharu.kotatsu.local.domain.model.LocalManga
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.util.longHashCode
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.toFileNameSafe
import java.io.File import java.io.File
/** /**

View File

@@ -10,12 +10,12 @@ import okhttp3.internal.closeQuietly
import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.util.ext.deleteAwait import org.koitharu.kotatsu.core.util.ext.deleteAwait
import org.koitharu.kotatsu.core.util.ext.takeIfReadable import org.koitharu.kotatsu.core.util.ext.takeIfReadable
import org.koitharu.kotatsu.core.util.ext.toFileNameSafe
import org.koitharu.kotatsu.core.zip.ZipOutput import org.koitharu.kotatsu.core.zip.ZipOutput
import org.koitharu.kotatsu.local.data.MangaIndex import org.koitharu.kotatsu.local.data.MangaIndex
import org.koitharu.kotatsu.local.data.input.LocalMangaParser import org.koitharu.kotatsu.local.data.input.LocalMangaParser
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.toFileNameSafe
import java.io.File import java.io.File
class LocalMangaDirOutput( class LocalMangaDirOutput(
@@ -96,7 +96,9 @@ class LocalMangaDirOutput(
} }
suspend fun deleteChapters(ids: Set<Long>) = mutex.withLock { suspend fun deleteChapters(ids: Set<Long>) = mutex.withLock {
val chapters = checkNotNull((index.getMangaInfo() ?: LocalMangaParser(rootFile).getManga(withDetails = true).manga).chapters) { val chapters = checkNotNull(
(index.getMangaInfo() ?: LocalMangaParser(rootFile).getManga(withDetails = true).manga).chapters,
) {
"No chapters found" "No chapters found"
}.withIndex() }.withIndex()
val victimsIds = ids.toMutableSet() val victimsIds = ids.toMutableSet()

View File

@@ -7,11 +7,11 @@ import kotlinx.coroutines.withContext
import okio.Closeable import okio.Closeable
import org.koitharu.kotatsu.core.prefs.DownloadFormat import org.koitharu.kotatsu.core.prefs.DownloadFormat
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.toFileNameSafe
import org.koitharu.kotatsu.local.data.input.LocalMangaParser import org.koitharu.kotatsu.local.data.input.LocalMangaParser
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.toFileNameSafe
import java.io.File import java.io.File
sealed class LocalMangaOutput( sealed class LocalMangaOutput(

View File

@@ -10,11 +10,11 @@ import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.util.ext.bookmarkKey import org.koitharu.kotatsu.core.util.ext.bookmarkKey
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.mangaKey import org.koitharu.kotatsu.core.util.ext.mangaKey
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.findById import org.koitharu.kotatsu.parsers.util.findById
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.util.Collections import java.util.Collections
import javax.inject.Inject import javax.inject.Inject

View File

@@ -31,12 +31,12 @@ import okio.source
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.isFileUri import org.koitharu.kotatsu.core.util.ext.isFileUri
import org.koitharu.kotatsu.core.util.ext.isZipUri import org.koitharu.kotatsu.core.util.ext.isZipUri
import org.koitharu.kotatsu.core.util.ext.toFileNameSafe
import org.koitharu.kotatsu.core.util.ext.toFileOrNull import org.koitharu.kotatsu.core.util.ext.toFileOrNull
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.util.toFileNameSafe
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat

View File

@@ -40,9 +40,7 @@ import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.core.util.ext.requireValue
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
import org.koitharu.kotatsu.details.data.MangaDetails import org.koitharu.kotatsu.details.data.MangaDetails
import org.koitharu.kotatsu.details.domain.DetailsInteractor import org.koitharu.kotatsu.details.domain.DetailsInteractor
import org.koitharu.kotatsu.details.domain.DetailsLoadUseCase import org.koitharu.kotatsu.details.domain.DetailsLoadUseCase
@@ -57,6 +55,8 @@ import org.koitharu.kotatsu.local.domain.DeleteLocalMangaUseCase
import org.koitharu.kotatsu.local.domain.model.LocalManga import org.koitharu.kotatsu.local.domain.model.LocalManga
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.parsers.util.sizeOrZero
import org.koitharu.kotatsu.reader.domain.ChaptersLoader import org.koitharu.kotatsu.reader.domain.ChaptersLoader
import org.koitharu.kotatsu.reader.domain.DetectReaderModeUseCase import org.koitharu.kotatsu.reader.domain.DetectReaderModeUseCase
import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.domain.PageLoader

View File

@@ -8,9 +8,9 @@ import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.ParserMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.mapToArray
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.mapToArray
import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrNull import org.koitharu.kotatsu.parsers.util.suspendlazy.getOrNull
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import kotlin.coroutines.resume import kotlin.coroutines.resume

View File

@@ -26,7 +26,6 @@ import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.getCauseUrl import org.koitharu.kotatsu.core.util.ext.getCauseUrl
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.domain.ExploreRepository
@@ -40,6 +39,7 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.toErrorFooter import org.koitharu.kotatsu.list.ui.model.toErrorFooter
import org.koitharu.kotatsu.list.ui.model.toErrorState import org.koitharu.kotatsu.list.ui.model.toErrorState
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.sizeOrZero
import javax.inject.Inject import javax.inject.Inject
private const val FILTER_MIN_INTERVAL = 250L private const val FILTER_MIN_INTERVAL = 250L

View File

@@ -21,11 +21,11 @@ import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.widgets.ChipsView import org.koitharu.kotatsu.core.ui.widgets.ChipsView
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.mapToSet import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.parsers.util.sizeOrZero
import org.koitharu.kotatsu.search.domain.MangaSearchRepository import org.koitharu.kotatsu.search.domain.MangaSearchRepository
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
import javax.inject.Inject import javax.inject.Inject

View File

@@ -10,6 +10,7 @@ import androidx.preference.Preference
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.combine
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.github.AppVersion
@@ -29,10 +30,8 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
addPreferencesFromResource(R.xml.pref_about) addPreferencesFromResource(R.xml.pref_about)
findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.run { findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.run {
title = getString(R.string.app_version, BuildConfig.VERSION_NAME) title = getString(R.string.app_version, BuildConfig.VERSION_NAME)
isEnabled = viewModel.isUpdateSupported
} }
findPreference<SwitchPreferenceCompat>(AppSettings.KEY_UPDATES_UNSTABLE)?.run { findPreference<SwitchPreferenceCompat>(AppSettings.KEY_UPDATES_UNSTABLE)?.run {
isVisible = viewModel.isUpdateSupported
isEnabled = VersionId(BuildConfig.VERSION_NAME).isStable isEnabled = VersionId(BuildConfig.VERSION_NAME).isStable
if (!isEnabled) isChecked = true if (!isEnabled) isChecked = true
} }
@@ -40,9 +39,12 @@ class AboutSettingsFragment : BasePreferenceFragment(R.string.about) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
viewModel.isLoading.observe(viewLifecycleOwner) { combine(viewModel.isUpdateSupported, viewModel.isLoading, ::Pair)
findPreference<Preference>(AppSettings.KEY_APP_UPDATE)?.isEnabled = !it .observe(viewLifecycleOwner) { (isUpdateSupported, isLoading) ->
} findPreference<Preference>(AppSettings.KEY_UPDATES_UNSTABLE)?.isVisible = isUpdateSupported
findPreference<Preference>(AppSettings.KEY_APP_VERSION)?.isEnabled = isUpdateSupported && !isLoading
}
viewModel.onUpdateAvailable.observeEvent(viewLifecycleOwner, ::onUpdateAvailable) viewModel.onUpdateAvailable.observeEvent(viewLifecycleOwner, ::onUpdateAvailable)
} }

View File

@@ -1,6 +1,10 @@
package org.koitharu.kotatsu.settings.about package org.koitharu.kotatsu.settings.about
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.github.AppUpdateRepository
import org.koitharu.kotatsu.core.github.AppVersion import org.koitharu.kotatsu.core.github.AppVersion
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
@@ -13,7 +17,10 @@ class AboutSettingsViewModel @Inject constructor(
private val appUpdateRepository: AppUpdateRepository, private val appUpdateRepository: AppUpdateRepository,
) : BaseViewModel() { ) : BaseViewModel() {
val isUpdateSupported = appUpdateRepository.isUpdateSupported() val isUpdateSupported = flow {
emit(appUpdateRepository.isUpdateSupported())
}.stateIn(viewModelScope, SharingStarted.Eagerly, false)
val onUpdateAvailable = MutableEventFlow<AppVersion?>() val onUpdateAvailable = MutableEventFlow<AppVersion?>()
fun checkForUpdates() { fun checkForUpdates() {

View File

@@ -10,9 +10,9 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.EmptyMangaRepository import org.koitharu.kotatsu.core.parser.EmptyMangaRepository
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.ParserMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.mapToArray
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.mapToArray
import org.koitharu.kotatsu.settings.utils.AutoCompleteTextViewPreference import org.koitharu.kotatsu.settings.utils.AutoCompleteTextViewPreference
import org.koitharu.kotatsu.settings.utils.EditTextBindListener import org.koitharu.kotatsu.settings.utils.EditTextBindListener
import org.koitharu.kotatsu.settings.utils.EditTextDefaultSummaryProvider import org.koitharu.kotatsu.settings.utils.EditTextDefaultSummaryProvider
@@ -119,6 +119,6 @@ private fun PreferenceFragmentCompat.addPreferencesFromEmptyRepository() {
preferenceScreen.addPreference(preference) preferenceScreen.addPreference(preference)
} }
private fun Array<out String>.toStringArray(): Array<String> { private fun Array<out String?>.toStringArray(): Array<String> {
return Array(size) { i -> this[i] as? String ?: "" } return Array(size) { i -> this[i].orEmpty() }
} }

View File

@@ -16,4 +16,4 @@ class EditTextDefaultSummaryProvider(
text text
} }
} }
} }

View File

@@ -1,8 +1,8 @@
package org.koitharu.kotatsu.suggestions.domain package org.koitharu.kotatsu.suggestions.domain
import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.almostEquals
class TagsBlacklist( class TagsBlacklist(
private val tags: Set<String>, private val tags: Set<String>,

View File

@@ -51,7 +51,6 @@ import org.koitharu.kotatsu.core.model.distinctById
import org.koitharu.kotatsu.core.model.isNsfw import org.koitharu.kotatsu.core.model.isNsfw
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.almostEquals
import org.koitharu.kotatsu.core.util.ext.asArrayList import org.koitharu.kotatsu.core.util.ext.asArrayList
import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName
import org.koitharu.kotatsu.core.util.ext.awaitWorkInfosByTag import org.koitharu.kotatsu.core.util.ext.awaitWorkInfosByTag
@@ -60,7 +59,6 @@ import org.koitharu.kotatsu.core.util.ext.flatten
import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra import org.koitharu.kotatsu.core.util.ext.mangaSourceExtra
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.sanitize import org.koitharu.kotatsu.core.util.ext.sanitize
import org.koitharu.kotatsu.core.util.ext.sizeOrZero
import org.koitharu.kotatsu.core.util.ext.takeMostFrequent import org.koitharu.kotatsu.core.util.ext.takeMostFrequent
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
import org.koitharu.kotatsu.core.util.ext.trySetForeground import org.koitharu.kotatsu.core.util.ext.trySetForeground
@@ -73,7 +71,9 @@ import org.koitharu.kotatsu.parsers.model.MangaListFilter
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.almostEquals
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.sizeOrZero
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler import org.koitharu.kotatsu.settings.work.PeriodicWorkScheduler

View File

@@ -6,7 +6,7 @@ import android.content.Context
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import javax.inject.Inject import javax.inject.Inject
class SyncSettings( class SyncSettings(

View File

@@ -13,9 +13,9 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.AlertDialogFragment import org.koitharu.kotatsu.core.ui.AlertDialogFragment
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.withArgs import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.PreferenceDialogAutocompletetextviewBinding import org.koitharu.kotatsu.databinding.PreferenceDialogAutocompletetextviewBinding
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
import org.koitharu.kotatsu.settings.utils.validation.UrlValidator import org.koitharu.kotatsu.settings.utils.validation.UrlValidator
import org.koitharu.kotatsu.sync.data.SyncSettings import org.koitharu.kotatsu.sync.data.SyncSettings
import javax.inject.Inject import javax.inject.Inject

View File

@@ -11,12 +11,12 @@ import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.toManga import org.koitharu.kotatsu.core.db.entity.toManga
import org.koitharu.kotatsu.core.db.entity.toMangaTags import org.koitharu.kotatsu.core.db.entity.toMangaTags
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.ifZero
import org.koitharu.kotatsu.core.util.ext.mapItems import org.koitharu.kotatsu.core.util.ext.mapItems
import org.koitharu.kotatsu.core.util.ext.toInstantOrNull import org.koitharu.kotatsu.core.util.ext.toInstantOrNull
import org.koitharu.kotatsu.details.domain.ProgressUpdateUseCase import org.koitharu.kotatsu.details.domain.ProgressUpdateUseCase
import org.koitharu.kotatsu.list.domain.ListFilterOption import org.koitharu.kotatsu.list.domain.ListFilterOption
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.ifZero
import org.koitharu.kotatsu.tracker.data.TrackEntity import org.koitharu.kotatsu.tracker.data.TrackEntity
import org.koitharu.kotatsu.tracker.data.TrackLogEntity import org.koitharu.kotatsu.tracker.data.TrackLogEntity
import org.koitharu.kotatsu.tracker.data.toTrackingLogItem import org.koitharu.kotatsu.tracker.data.toTrackingLogItem

View File

@@ -1,9 +1,9 @@
package org.koitharu.kotatsu.tracker.domain.model package org.koitharu.kotatsu.tracker.domain.model
import org.koitharu.kotatsu.core.util.ext.ifZero
import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import org.koitharu.kotatsu.parsers.util.ifZero
sealed interface MangaUpdates { sealed interface MangaUpdates {

5
app/version.properties Normal file
View File

@@ -0,0 +1,5 @@
#Wed Jan 22 19:14:17 EET 2025
code=1
build=8
variant=
base=7.7

View File

@@ -31,7 +31,7 @@ material = "1.12.0"
moshi = "1.15.2" moshi = "1.15.2"
okhttp = "4.12.0" okhttp = "4.12.0"
okio = "3.9.1" okio = "3.9.1"
parsers = "8481fadbd0" parsers = "51ed1b2db8"
preference = "1.2.1" preference = "1.2.1"
recyclerview = "1.3.2" recyclerview = "1.3.2"
room = "2.6.1" room = "2.6.1"