Fixes and refactor

This commit is contained in:
Koitharu
2021-01-17 18:30:14 +02:00
parent a242aa6633
commit 8f8d85d172
41 changed files with 119 additions and 127 deletions

View File

@@ -9,7 +9,6 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.koitharu.kotatsu.utils.ext.safe
class BrowserClient(private val callback: BrowserCallback) : WebViewClient(), KoinComponent {
@@ -45,7 +44,7 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClient(), Ko
return request?.url?.toString()?.let(::doRequest)
}
private fun doRequest(url: String): WebResourceResponse? = safe {
private fun doRequest(url: String): WebResourceResponse? = runCatching {
val request = Request.Builder()
.url(url)
.build()
@@ -56,5 +55,5 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClient(), Ko
ct?.charset()?.name() ?: "utf-8",
response.body?.byteStream()
)
}
}.getOrNull()
}

View File

@@ -4,7 +4,9 @@ import okhttp3.CookieJar
import okhttp3.OkHttpClient
import org.koin.android.ext.koin.androidContext
import org.koin.core.qualifier.named
import org.koin.dsl.bind
import org.koin.dsl.module
import org.koitharu.kotatsu.core.network.cookies.ClearableCookieJar
import org.koitharu.kotatsu.core.network.cookies.PersistentCookieJar
import org.koitharu.kotatsu.core.network.cookies.cache.SetCookieCache
import org.koitharu.kotatsu.core.network.cookies.persistence.SharedPrefsCookiePersistor
@@ -18,7 +20,7 @@ val networkModule
SetCookieCache(),
SharedPrefsCookiePersistor(androidContext())
)
}
} bind ClearableCookieJar::class
single(named(CacheUtils.QUALIFIER_HTTP)) { CacheUtils.createHttpCache(androidContext()) }
single {
OkHttpClient.Builder().apply {

View File

@@ -2,16 +2,22 @@ package org.koitharu.kotatsu.core.network
import android.os.Build
import okhttp3.Interceptor
import okhttp3.Response
import org.koitharu.kotatsu.BuildConfig
import java.util.*
class UserAgentInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain) = chain.proceed(
chain.request().newBuilder()
.header(HEADER_USER_AGENT, userAgent)
.build()
)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
return chain.proceed(
if (request.header(HEADER_USER_AGENT) == null) {
request.newBuilder()
.header(HEADER_USER_AGENT, userAgent)
.build()
} else request
)
}
companion object {

View File

@@ -35,7 +35,7 @@ class PersistentCookieJar(
cache.addAll(persistor.loadAll())
}
cache.addAll(cookies)
persistor.saveAll(filterPersistentCookies(cookies))
persistor.saveAll(cookies.filter { it.persistent })
}
@Synchronized
@@ -48,11 +48,14 @@ class PersistentCookieJar(
val it = cache.iterator()
while (it.hasNext()) {
val currentCookie = it.next()
if (isCookieExpired(currentCookie)) {
cookiesToRemove.add(currentCookie)
it.remove()
} else if (currentCookie.matches(url)) {
validCookies.add(currentCookie)
when {
currentCookie.isExpired() -> {
cookiesToRemove.add(currentCookie)
it.remove()
}
currentCookie.matches(url) -> {
validCookies.add(currentCookie)
}
}
}
persistor.removeAll(cookiesToRemove)
@@ -73,18 +76,8 @@ class PersistentCookieJar(
private companion object {
fun filterPersistentCookies(cookies: List<Cookie>): List<Cookie> {
val persistentCookies: MutableList<Cookie> = ArrayList()
for (cookie in cookies) {
if (cookie.persistent) {
persistentCookies.add(cookie)
}
}
return persistentCookies
}
fun isCookieExpired(cookie: Cookie): Boolean {
return cookie.expiresAt < System.currentTimeMillis()
fun Cookie.isExpired(): Boolean {
return expiresAt < System.currentTimeMillis()
}
}
}

View File

@@ -19,7 +19,7 @@ val parserModule
factory<MangaRepository>(named(MangaSource.HENCHAN)) { HenChanRepository(get()) }
factory<MangaRepository>(named(MangaSource.YAOICHAN)) { YaoiChanRepository(get()) }
factory<MangaRepository>(named(MangaSource.MANGATOWN)) { MangaTownRepository(get()) }
factory<MangaRepository>(named(MangaSource.MANGALIB)) { MangaLibRepository(get()) }
single<MangaRepository>(named(MangaSource.MANGALIB)) { MangaLibRepository(get()) }
factory<MangaRepository>(named(MangaSource.NUDEMOON)) { NudeMoonRepository(get()) }
factory<MangaRepository>(named(MangaSource.MANGAREAD)) { MangareadRepository(get()) }
}

View File

@@ -56,7 +56,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
).firstOrNull()?.text(),
coverUrl = row.selectFirst("div.manga_images")?.selectFirst("img")
?.attr("src")?.withDomain(domain).orEmpty(),
tags = safe {
tags = runCatching {
row.selectFirst("div.genre")?.select("a")?.mapToSet {
MangaTag(
title = it.text(),
@@ -64,7 +64,7 @@ abstract class ChanRepository(loaderContext: MangaLoaderContext) : RemoteMangaRe
source = source
)
}
}.orEmpty(),
}.getOrNull().orEmpty(),
source = source
)
}

View File

@@ -1,7 +1,7 @@
package org.koitharu.kotatsu.core.parser.site
import androidx.collection.arraySetOf
import androidx.core.net.toUri
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
import org.koitharu.kotatsu.core.exceptions.ParseException
import org.koitharu.kotatsu.core.model.*
@@ -53,7 +53,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
}.parseHtml()
val root = doc.body().getElementById("mangaBox")
?.selectFirst("div.tiles.row") ?: throw ParseException("Cannot find root")
val baseHost = root.baseUri().toUri().host
val baseHost = root.baseUri().toHttpUrl().host
return root.select("div.tile").mapNotNull { node ->
val imgDiv = node.selectFirst("div.img") ?: return@mapNotNull null
val descDiv = node.selectFirst("div.desc") ?: return@mapNotNull null
@@ -61,7 +61,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
return@mapNotNull null //skip author
}
val href = imgDiv.selectFirst("a").attr("href")?.inContextOf(node)
if (href == null || href.toUri().host != baseHost) {
if (href == null || href.toHttpUrl().host != baseHost) {
return@mapNotNull null // skip external links
}
val title = descDiv.selectFirst("h3")?.selectFirst("a")?.text()
@@ -73,15 +73,15 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
title = title,
altTitle = descDiv.selectFirst("h4")?.text(),
coverUrl = imgDiv.selectFirst("img.lazy")?.attr("data-original").orEmpty(),
rating = safe {
rating = runCatching {
node.selectFirst("div.rating")
?.attr("title")
?.substringBefore(' ')
?.toFloatOrNull()
?.div(10f)
} ?: Manga.NO_RATING,
}.getOrNull() ?: Manga.NO_RATING,
author = tileInfo?.selectFirst("a.person-link")?.text(),
tags = safe {
tags = runCatching {
tileInfo?.select("a.element-link")
?.mapToSet {
MangaTag(
@@ -90,7 +90,7 @@ abstract class GroupleRepository(loaderContext: MangaLoaderContext) :
source = source
)
}
}.orEmpty(),
}.getOrNull().orEmpty(),
state = when {
node.selectFirst("div.tags")
?.selectFirst("span.mangaCompleted") != null -> MangaState.FINISHED

View File

@@ -80,14 +80,14 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
val title = root.selectFirst("div.media-header__wrap")?.children()
val info = root.selectFirst("div.media-content")
val chaptersDoc = loaderContext.httpGet(manga.url + "?section=chapters").parseHtml()
val scripts = chaptersDoc.body().select("script")
val scripts = chaptersDoc.select("script")
var chapters: ArrayList<MangaChapter>? = null
scripts@ for (script in scripts) {
val raw = script.html().lines()
for (line in raw) {
if (line.startsWith("window.__CHAPTERS_DATA__")) {
if (line.startsWith("window.__DATA__")) {
val json = JSONObject(line.substringAfter('=').substringBeforeLast(';'))
val list = json.getJSONArray("list")
val list = json.getJSONObject("chapters").getJSONArray("list")
val total = list.length()
chapters = ArrayList(total)
for (i in 0 until total) {
@@ -99,7 +99,7 @@ open class MangaLibRepository(loaderContext: MangaLoaderContext) :
append("/c")
append(item.getString("chapter_number"))
append('/')
append(item.getJSONArray("teams").getJSONObject(0).optString("slug"))
append(item.optString("chapter_string"))
}
var name = item.getString("chapter_name")
if (name.isNullOrBlank() || name == "null") {

View File

@@ -149,6 +149,7 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
const val KEY_SOURCES_HIDDEN = "sources_hidden"
const val KEY_TRAFFIC_WARNING = "traffic_warning"
const val KEY_PAGES_CACHE_CLEAR = "pages_cache_clear"
const val KEY_COOKIES_CLEAR = "cookies_clear"
const val KEY_THUMBS_CACHE_CLEAR = "thumbs_cache_clear"
const val KEY_SEARCH_HISTORY_CLEAR = "search_history_clear"
const val KEY_UPDATES_FEED_CLEAR = "updates_feed_clear"

View File

@@ -17,7 +17,6 @@ import org.koitharu.kotatsu.history.domain.HistoryRepository
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.safe
import java.io.IOException
class DetailsViewModel(
@@ -93,7 +92,7 @@ class DetailsViewModel(
launchLoadingJob(Dispatchers.Default) {
val original = localMangaRepository.getRemoteManga(manga)
localMangaRepository.delete(manga) || throw IOException("Unable to delete file")
safe {
runCatching {
historyRepository.deleteOrSwap(manga, original)
}
onMangaRemoved.postCall(manga)

View File

@@ -92,13 +92,13 @@ class DownloadService : BaseService() {
var output: MangaZip? = null
try {
val repo = manga.source.repository
val cover = safe {
val cover = runCatching {
imageLoader.execute(
ImageRequest.Builder(this@DownloadService)
.data(manga.coverUrl)
.build()
).drawable
}
}.getOrNull()
notification.setLargeIcon(cover)
notification.update()
val data = if (manga.chapters == null) repo.getDetails(manga) else manga

View File

@@ -9,7 +9,6 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.MangaTag
import org.koitharu.kotatsu.utils.ext.getStringOrNull
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.safe
class MangaIndex(source: String?) {
@@ -40,7 +39,7 @@ class MangaIndex(source: String?) {
json.put("app_version", BuildConfig.VERSION_CODE)
}
fun getMangaInfo(): Manga? = if (json.length() == 0) null else safe {
fun getMangaInfo(): Manga? = if (json.length() == 0) null else runCatching {
val source = MangaSource.valueOf(json.getString("source"))
Manga(
id = json.getLong("id"),
@@ -60,7 +59,7 @@ class MangaIndex(source: String?) {
},
chapters = getChapters(json.getJSONObject("chapters"), source)
)
}
}.getOrNull()
fun getCoverEntry(): String? = json.optString("cover_entry")

View File

@@ -15,7 +15,6 @@ import org.koitharu.kotatsu.local.data.MangaZip
import org.koitharu.kotatsu.utils.AlphanumComparator
import org.koitharu.kotatsu.utils.ext.longHashCode
import org.koitharu.kotatsu.utils.ext.readText
import org.koitharu.kotatsu.utils.ext.safe
import org.koitharu.kotatsu.utils.ext.sub
import java.io.File
import java.util.*
@@ -37,7 +36,7 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
}
val files = getAvailableStorageDirs(context)
.flatMap { x -> x.listFiles(filenameFilter)?.toList().orEmpty() }
return files.mapNotNull { x -> safe { getFromFile(x) } }
return files.mapNotNull { x -> runCatching { getFromFile(x) }.getOrNull() }
}
override suspend fun getDetails(manga: Manga) = if (manga.chapters == null) {
@@ -128,9 +127,9 @@ class LocalMangaRepository(private val context: Context) : MangaRepository {
}
fun getRemoteManga(localManga: Manga): Manga? {
val file = safe {
val file = runCatching {
Uri.parse(localManga.url).toFile()
} ?: return null
}.getOrNull() ?: return null
val zip = ZipFile(file)
val entry = zip.getEntry(MangaZip.INDEX_ENTRY)
val index = entry?.let(zip::readText)?.let(::MangaIndex) ?: return null

View File

@@ -22,7 +22,6 @@ import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.utils.MediaStoreCompat
import org.koitharu.kotatsu.utils.SingleLiveEvent
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
import org.koitharu.kotatsu.utils.ext.safe
import org.koitharu.kotatsu.utils.ext.sub
import java.io.IOException
@@ -49,7 +48,10 @@ class LocalListViewModel(
list.isEmpty() -> listOf(EmptyState(R.string.text_local_holder))
else -> list.toUi(mode)
}
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
}.asLiveDataDistinct(
viewModelScope.coroutineContext + Dispatchers.Default,
listOf(LoadingState)
)
init {
onRefresh()
@@ -94,7 +96,7 @@ class LocalListViewModel(
withContext(Dispatchers.Default) {
val original = repository.getRemoteManga(manga)
repository.delete(manga) || throw IOException("Unable to delete file")
safe {
runCatching {
historyRepository.deleteOrSwap(manga, original)
}
}

View File

@@ -1,4 +1,4 @@
package org.koitharu.kotatsu.reader.ui
package org.koitharu.kotatsu.reader.domain
import android.graphics.Bitmap
import android.graphics.BitmapFactory

View File

@@ -5,7 +5,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
abstract class BasePageHolder<B : ViewBinding>(
protected val binding: B,

View File

@@ -8,7 +8,7 @@ import androidx.viewbinding.ViewBinding
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.ReaderViewModel

View File

@@ -6,7 +6,7 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.utils.ext.resetTransformations
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

View File

@@ -9,7 +9,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.utils.ext.launchAfter
import org.koitharu.kotatsu.utils.ext.launchInstead
import java.io.File

View File

@@ -6,7 +6,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.standard.PageHolder
class ReversedPageHolder(

View File

@@ -5,7 +5,7 @@ import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class ReversedPagesAdapter(

View File

@@ -12,7 +12,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.BasePageHolder
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.getDisplayMessage

View File

@@ -5,7 +5,7 @@ import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class PagesAdapter(

View File

@@ -5,7 +5,7 @@ import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class WebtoonAdapter(

View File

@@ -11,7 +11,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.ui.PageLoader
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.pager.BasePageHolder
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.getDisplayMessage

View File

@@ -7,7 +7,6 @@ import android.view.MenuItem
import androidx.appcompat.widget.SearchView
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.search.ui.global.GlobalSearchActivity
import org.koitharu.kotatsu.utils.ext.safe
import java.io.Closeable
object SearchHelper {
@@ -43,10 +42,10 @@ object SearchHelper {
override fun onSuggestionSelect(position: Int) = false
override fun onSuggestionClick(position: Int): Boolean {
val query = safe {
val query = runCatching {
val c = view.suggestionsAdapter.getItem(position) as? Cursor
c?.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY))
} ?: return false
}.getOrNull() ?: return false
view.setQuery(query, true)
return true
}

View File

@@ -7,9 +7,11 @@ import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.network.cookies.ClearableCookieJar
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.Cache
import org.koitharu.kotatsu.search.ui.MangaSuggestionsProvider
@@ -71,6 +73,20 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
clearCache(preference, Cache.THUMBS)
true
}
AppSettings.KEY_COOKIES_CLEAR -> {
viewLifecycleScope.launch {
val cookieJar = get<ClearableCookieJar>()
withContext(Dispatchers.IO) {
cookieJar.clear()
}
Snackbar.make(
listView ?: return@launch,
R.string.cookies_cleared,
Snackbar.LENGTH_SHORT
).show()
}
true
}
AppSettings.KEY_SEARCH_HISTORY_CLEAR -> {
viewLifecycleScope.launch {
MangaSuggestionsProvider.clearHistory(preference.context)

View File

@@ -9,18 +9,18 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.safe
class SourcesAdapter(
private val settings: AppSettings,
private val onItemClickListener: OnListItemClickListener<MangaSource>,
) : RecyclerView.Adapter<SourceViewHolder>() {
private val dataSet = MangaProviderFactory.getSources(settings, includeHidden = true).toMutableList()
private val dataSet =
MangaProviderFactory.getSources(settings, includeHidden = true).toMutableList()
private val hiddenItems = settings.hiddenSources.mapNotNull {
safe {
runCatching {
MangaSource.valueOf(it)
}
}.getOrNull()
}.toMutableSet()
override fun onCreateViewHolder(

View File

@@ -21,7 +21,6 @@ import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
import org.koitharu.kotatsu.utils.ext.safe
import org.koitharu.kotatsu.utils.ext.toBitmapOrNull
import org.koitharu.kotatsu.utils.ext.toUriOrNull
import java.util.concurrent.TimeUnit
@@ -37,23 +36,23 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
private val repository by inject<TrackingRepository>()
private val settings by inject<AppSettings>()
override suspend fun doWork(): Result = withContext(Dispatchers.Default) {
override suspend fun doWork(): Result {
val trackSources = settings.trackSources
if (trackSources.isEmpty()) {
return@withContext Result.success()
return Result.success()
}
val tracks = repository.getAllTracks(
useFavourites = AppSettings.TRACK_FAVOURITES in trackSources,
useHistory = AppSettings.TRACK_HISTORY in trackSources
)
if (tracks.isEmpty()) {
return@withContext Result.success()
return Result.success()
}
var success = 0
for (track in tracks) {
val details = safe {
val details = runCatching {
track.manga.source.repository.getDetails(track.manga)
}
}.getOrNull()
val chapters = details?.chapters ?: continue
when {
track.knownChaptersCount == -1 -> { //first check
@@ -125,7 +124,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
success++
}
repository.cleanup()
if (success == 0) {
return if (success == 0) {
Result.retry()
} else {
Result.success()

View File

@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.utils.ext
import android.content.res.Resources
import android.util.Log
import kotlinx.coroutines.delay
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
@@ -12,15 +11,6 @@ import org.koitharu.kotatsu.core.exceptions.WrongPasswordException
import java.io.FileNotFoundException
import java.net.SocketTimeoutException
inline fun <T, R> T.safe(action: T.() -> R?) = try {
this.action()
} catch (e: Throwable) {
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
null
}
suspend inline fun <T, R> T.retryUntilSuccess(maxAttempts: Int, action: T.() -> R): R {
var attempts = maxAttempts
while (true) {

View File

@@ -35,11 +35,11 @@ inline fun File.findParent(predicate: (File) -> Boolean): File? {
return current
}
fun File.getStorageName(context: Context): String = safe {
fun File.getStorageName(context: Context): String = runCatching {
val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
manager.getStorageVolume(this)?.getDescription(context)?.let {
return@safe it
return@runCatching it
}
}
when {
@@ -47,6 +47,6 @@ fun File.getStorageName(context: Context): String = safe {
Environment.isExternalStorageRemovable(this) -> context.getString(R.string.external_storage)
else -> null
}
} ?: context.getString(R.string.other_storage)
}.getOrNull() ?: context.getString(R.string.other_storage)
fun Uri.toFileOrNull() = if (scheme == "file") path?.let(::File) else null

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_list_mode"
android:orderInCategory="20"
android:title="@string/list_mode"
app:showAsAction="never" />
</menu>

View File

@@ -190,4 +190,6 @@
<string name="silent">Без звука</string>
<string name="captcha_required">Необходимо пройти CAPTCHA</string>
<string name="resolve">Resolve</string>
<string name="clear_cookies">Очистить куки</string>
<string name="cookies_cleared">Все куки удалены</string>
</resources>

View File

@@ -192,4 +192,6 @@
<string name="silent">Silent</string>
<string name="captcha_required">CAPTCHA is required</string>
<string name="resolve">Resolve</string>
<string name="clear_cookies">Clear cookies</string>
<string name="cookies_cleared">All cookies was removed</string>
</resources>

View File

@@ -8,13 +8,6 @@
<item name="android:paddingBottom">10dp</item>
</style>
<style name="AppToggleButton.Vertical" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:checkable">true</item>
<item name="android:gravity">center_horizontal</item>
<item name="iconPadding">6dp</item>
<item name="iconGravity">top</item>
</style>
<style name="AppPopupTheme" parent="ThemeOverlay.MaterialComponents.Light" />
<style name="AppToolbarTheme" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar">
@@ -32,8 +25,4 @@
<item name="background">@color/grey</item>
</style>
<style name="AppBadge" parent="Widget.MaterialComponents.Badge">
<item name="backgroundColor">?attr/colorAccent</item>
</style>
</resources>

View File

@@ -16,8 +16,8 @@
app:iconSpaceReserved="false" />
<PreferenceCategory
app:iconSpaceReserved="false"
android:title="@string/cache">
android:title="@string/cache"
app:iconSpaceReserved="false">
<Preference
android:key="thumbs_cache_clear"
@@ -33,4 +33,10 @@
</PreferenceCategory>
<Preference
android:key="cookies_clear"
android:persistent="false"
android:title="@string/clear_cookies"
app:iconSpaceReserved="false" />
</PreferenceScreen>