Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b8afe9c40 | ||
|
|
754ccc4197 | ||
|
|
ef691b1aed |
@@ -18,8 +18,8 @@ android {
|
||||
applicationId 'org.koitharu.kotatsu'
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
versionCode = 694
|
||||
versionName = '7.7.2'
|
||||
versionCode = 695
|
||||
versionName = '7.7.3'
|
||||
generatedDensities = []
|
||||
testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner'
|
||||
ksp {
|
||||
|
||||
@@ -3,5 +3,5 @@ package org.koitharu.kotatsu.core.exceptions
|
||||
import okio.IOException
|
||||
|
||||
class NoDataReceivedException(
|
||||
url: String,
|
||||
val url: String,
|
||||
) : IOException("No data has been received from $url")
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.find
|
||||
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
|
||||
import java.io.File
|
||||
import java.net.Proxy
|
||||
@@ -412,10 +413,10 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
get() = prefs.getString(KEY_PROXY_PORT, null)?.toIntOrNull() ?: 0
|
||||
|
||||
val proxyLogin: String?
|
||||
get() = prefs.getString(KEY_PROXY_LOGIN, null)?.takeUnless { it.isEmpty() }
|
||||
get() = prefs.getString(KEY_PROXY_LOGIN, null)?.nullIfEmpty()
|
||||
|
||||
val proxyPassword: String?
|
||||
get() = prefs.getString(KEY_PROXY_PASSWORD, null)?.takeUnless { it.isEmpty() }
|
||||
get() = prefs.getString(KEY_PROXY_PASSWORD, null)?.nullIfEmpty()
|
||||
|
||||
var localListOrder: SortOrder
|
||||
get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST)
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.settings.utils.validation.DomainValidator
|
||||
|
||||
class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig {
|
||||
@@ -38,7 +39,7 @@ class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig
|
||||
|
||||
is ConfigKey.ShowSuspiciousContent -> prefs.getBoolean(key.key, key.defaultValue)
|
||||
is ConfigKey.SplitByTranslations -> prefs.getBoolean(key.key, key.defaultValue)
|
||||
is ConfigKey.PreferredImageServer -> prefs.getString(key.key, key.defaultValue)?.takeUnless(String::isEmpty)
|
||||
is ConfigKey.PreferredImageServer -> prefs.getString(key.key, key.defaultValue)?.nullIfEmpty()
|
||||
} as T
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.storage.StorageManager
|
||||
import android.provider.DocumentsContract
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.parsers.util.removeSuffix
|
||||
import java.io.File
|
||||
import java.lang.reflect.Array as ArrayReflect
|
||||
@@ -80,7 +81,7 @@ private fun getVolumePathForAndroid11AndAbove(volumeId: String, context: Context
|
||||
private fun getVolumeIdFromTreeUri(treeUri: Uri): String? {
|
||||
val docId = DocumentsContract.getTreeDocumentId(treeUri)
|
||||
val split = docId.split(":".toRegex())
|
||||
return split.firstOrNull()?.takeUnless { it.isEmpty() }
|
||||
return split.firstOrNull()?.nullIfEmpty()
|
||||
}
|
||||
|
||||
private fun getDocumentPathFromTreeUri(treeUri: Uri): String? {
|
||||
|
||||
@@ -142,6 +142,7 @@ fun Throwable.getCauseUrl(): String? = when (this) {
|
||||
is NotFoundException -> url
|
||||
is TooManyRequestExceptions -> url
|
||||
is CaughtException -> cause?.getCauseUrl()
|
||||
is NoDataReceivedException -> url
|
||||
is CloudFlareBlockedException -> url
|
||||
is CloudFlareProtectedException -> url
|
||||
is HttpStatusException -> url
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
import org.koitharu.kotatsu.core.util.ext.setTextColorAttr
|
||||
import org.koitharu.kotatsu.databinding.ItemPageThumbBinding
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
fun pageThumbnailAD(
|
||||
@@ -36,7 +37,7 @@ fun pageThumbnailAD(
|
||||
AdapterDelegateClickListenerAdapter(this, clickListener).attach(itemView)
|
||||
|
||||
bind {
|
||||
val data: Any = item.page.preview?.takeUnless { it.isEmpty() } ?: item.page.toMangaPage()
|
||||
val data: Any = item.page.preview?.nullIfEmpty() ?: item.page.toMangaPage()
|
||||
binding.imageViewThumb.newImageRequest(lifecycleOwner, data)?.run {
|
||||
defaultPlaceholders(context)
|
||||
size(thumbSize)
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.model.YEAR_MIN
|
||||
import org.koitharu.kotatsu.parsers.util.ifZero
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
|
||||
import org.koitharu.kotatsu.remotelist.ui.RemoteListFragment
|
||||
import org.koitharu.kotatsu.search.domain.MangaSearchRepository
|
||||
@@ -267,7 +268,7 @@ class FilterCoordinator @Inject constructor(
|
||||
}
|
||||
|
||||
fun setQuery(value: String?) {
|
||||
val newQuery = value?.trim()?.takeUnless { it.isEmpty() }
|
||||
val newQuery = value?.trim()?.nullIfEmpty()
|
||||
currentListFilter.update { oldValue ->
|
||||
if (capabilities.isSearchWithFiltersSupported || newQuery == null) {
|
||||
oldValue.copy(query = newQuery)
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.badge.BadgeUtils
|
||||
import com.google.android.material.badge.ExperimentalBadgeUtils
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
|
||||
@CheckResult
|
||||
fun View.bindBadge(badge: BadgeDrawable?, counter: Int): BadgeDrawable? {
|
||||
@@ -34,7 +35,7 @@ private fun View.bindBadgeImpl(
|
||||
if (counter > 0) {
|
||||
badgeDrawable.number = counter
|
||||
} else {
|
||||
badgeDrawable.text = text?.takeUnless { it.isEmpty() }
|
||||
badgeDrawable.text = text?.nullIfEmpty()
|
||||
}
|
||||
badgeDrawable.isVisible = true
|
||||
badgeDrawable.align(this)
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.koitharu.kotatsu.databinding.ActivityColorFilterBinding
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
import org.koitharu.kotatsu.parsers.util.format
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.reader.domain.ReaderColorFilter
|
||||
import javax.inject.Inject
|
||||
import com.google.android.material.R as materialR
|
||||
@@ -137,7 +138,7 @@ class ColorFilterConfigActivity :
|
||||
}
|
||||
|
||||
private fun loadPreview(page: MangaPage) {
|
||||
val data: Any = page.preview?.takeUnless { it.isEmpty() } ?: page
|
||||
val data: Any = page.preview?.nullIfEmpty() ?: page
|
||||
ImageRequest.Builder(this@ColorFilterConfigActivity)
|
||||
.data(data)
|
||||
.scale(Scale.FILL)
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.scrobbling.common.data
|
||||
import android.content.Context
|
||||
import androidx.core.content.edit
|
||||
import org.jsoup.internal.StringUtil.StringJoiner
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerService
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerUser
|
||||
|
||||
@@ -31,7 +32,7 @@ class ScrobblerStorage(context: Context, service: ScrobblerService) {
|
||||
ScrobblerUser(
|
||||
id = lines[0].toLong(),
|
||||
nickname = lines[1],
|
||||
avatar = lines[2].takeUnless(String::isEmpty),
|
||||
avatar = lines[2].nullIfEmpty(),
|
||||
service = ScrobblerService.valueOf(lines[3]),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import okhttp3.internal.closeQuietly
|
||||
import okio.IOException
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.parsers.util.mimeType
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.scrobbling.common.data.ScrobblerStorage
|
||||
@@ -34,7 +35,7 @@ class KitsuInterceptor(private val storage: ScrobblerStorage) : Interceptor {
|
||||
}
|
||||
if (response.mimeType?.toMediaTypeOrNull()?.subtype == SUBTYPE_HTML) {
|
||||
val message = runCatchingCancellable {
|
||||
response.parseHtml().title().takeUnless { it.isEmpty() }
|
||||
response.parseHtml().title().nullIfEmpty()
|
||||
}.onFailure {
|
||||
response.closeQuietly()
|
||||
}.getOrNull() ?: "Invalid response (${response.code})"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.koitharu.kotatsu.tracker.domain
|
||||
|
||||
import android.util.Log
|
||||
import coil3.request.CachePolicy
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.getPreferredBranch
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.parser.CachingMangaRepository
|
||||
@@ -11,6 +13,7 @@ import org.koitharu.kotatsu.core.util.ext.toInstantOrNull
|
||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||
import org.koitharu.kotatsu.local.data.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.util.findById
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.tracker.domain.model.MangaTracking
|
||||
import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates
|
||||
@@ -45,8 +48,9 @@ class CheckNewChaptersUseCase @Inject constructor(
|
||||
runCatchingCancellable {
|
||||
repository.updateTracks()
|
||||
val details = getFullManga(manga)
|
||||
val chapters = details.chapters ?: return@withLock
|
||||
val track = repository.getTrackOrNull(manga) ?: return@withLock
|
||||
val branch = checkNotNull(details.chapters?.findById(currentChapterId)).branch
|
||||
val chapters = details.getChapters(branch)
|
||||
val chapterIndex = chapters.indexOfFirst { x -> x.id == currentChapterId }
|
||||
val lastNewChapterIndex = chapters.size - track.newChapters
|
||||
val lastChapter = chapters.lastOrNull()
|
||||
@@ -70,7 +74,7 @@ class CheckNewChaptersUseCase @Inject constructor(
|
||||
|
||||
private suspend fun invokeImpl(track: MangaTracking): MangaUpdates = runCatchingCancellable {
|
||||
val details = getFullManga(track.manga)
|
||||
compare(track, details, getBranch(details))
|
||||
compare(track, details, getBranch(details, track.lastChapterId))
|
||||
}.getOrElse { error ->
|
||||
MangaUpdates.Failure(
|
||||
manga = track.manga,
|
||||
@@ -80,9 +84,17 @@ class CheckNewChaptersUseCase @Inject constructor(
|
||||
repository.saveUpdates(updates)
|
||||
}
|
||||
|
||||
private suspend fun getBranch(manga: Manga): String? {
|
||||
val history = historyRepository.getOne(manga)
|
||||
return manga.getPreferredBranch(history)
|
||||
private suspend fun getBranch(manga: Manga, trackChapterId: Long): String? {
|
||||
historyRepository.getOne(manga)?.let {
|
||||
manga.chapters?.findById(it.chapterId)
|
||||
}?.let {
|
||||
return it.branch
|
||||
}
|
||||
manga.chapters?.findById(trackChapterId)?.let {
|
||||
return it.branch
|
||||
}
|
||||
// fallback
|
||||
return manga.getPreferredBranch(null)
|
||||
}
|
||||
|
||||
private suspend fun getFullManga(manga: Manga): Manga = when {
|
||||
@@ -111,25 +123,29 @@ class CheckNewChaptersUseCase @Inject constructor(
|
||||
private fun compare(track: MangaTracking, manga: Manga, branch: String?): MangaUpdates.Success {
|
||||
if (track.isEmpty()) {
|
||||
// first check or manga was empty on last check
|
||||
return MangaUpdates.Success(manga, emptyList(), isValid = false)
|
||||
return MangaUpdates.Success(manga, branch, emptyList(), isValid = false)
|
||||
}
|
||||
val chapters = requireNotNull(manga.getChapters(branch))
|
||||
if (BuildConfig.DEBUG && chapters.findById(track.lastChapterId) == null) {
|
||||
Log.e("Tracker", "Chapter ${track.lastChapterId} not found")
|
||||
}
|
||||
val newChapters = chapters.takeLastWhile { x -> x.id != track.lastChapterId }
|
||||
return when {
|
||||
newChapters.isEmpty() -> {
|
||||
MangaUpdates.Success(
|
||||
manga = manga,
|
||||
branch = branch,
|
||||
newChapters = emptyList(),
|
||||
isValid = chapters.lastOrNull()?.id == track.lastChapterId,
|
||||
)
|
||||
}
|
||||
|
||||
newChapters.size == chapters.size -> {
|
||||
MangaUpdates.Success(manga, emptyList(), isValid = false)
|
||||
MangaUpdates.Success(manga, branch, emptyList(), isValid = false)
|
||||
}
|
||||
|
||||
else -> {
|
||||
MangaUpdates.Success(manga, newChapters, isValid = true)
|
||||
MangaUpdates.Success(manga, branch, newChapters, isValid = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +216,6 @@ class TrackingRepository @Inject constructor(
|
||||
}
|
||||
|
||||
private fun TrackEntity.mergeWith(updates: MangaUpdates): TrackEntity {
|
||||
val chapters = updates.manga.chapters.orEmpty()
|
||||
return when (updates) {
|
||||
is MangaUpdates.Failure -> TrackEntity(
|
||||
mangaId = mangaId,
|
||||
@@ -230,7 +229,7 @@ class TrackingRepository @Inject constructor(
|
||||
|
||||
is MangaUpdates.Success -> TrackEntity(
|
||||
mangaId = mangaId,
|
||||
lastChapterId = chapters.lastOrNull()?.id ?: NO_ID,
|
||||
lastChapterId = updates.manga.getChapters(updates.branch).lastOrNull()?.id ?: NO_ID,
|
||||
newChapters = if (updates.isValid) newChapters + updates.newChapters.size else 0,
|
||||
lastCheckTime = System.currentTimeMillis(),
|
||||
lastChapterDate = updates.lastChapterDate().ifZero { lastChapterDate },
|
||||
|
||||
@@ -11,6 +11,7 @@ sealed interface MangaUpdates {
|
||||
|
||||
data class Success(
|
||||
override val manga: Manga,
|
||||
val branch: String?,
|
||||
val newChapters: List<MangaChapter>,
|
||||
val isValid: Boolean,
|
||||
) : MangaUpdates {
|
||||
|
||||
@@ -28,10 +28,10 @@ leakcanary = "3.0-alpha-8"
|
||||
lifecycle = "2.8.7"
|
||||
markwon = "4.6.2"
|
||||
material = "1.12.0"
|
||||
moshi = "1.15.1"
|
||||
moshi = "1.15.2"
|
||||
okhttp = "4.12.0"
|
||||
okio = "3.9.1"
|
||||
parsers = "fece09b781"
|
||||
parsers = "f86d31f811"
|
||||
preference = "1.2.1"
|
||||
recyclerview = "1.3.2"
|
||||
room = "2.6.1"
|
||||
|
||||
Reference in New Issue
Block a user