From 0badf10a8b044b6398d02e2de1bca93b4f7dc2a0 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 19 May 2025 19:11:46 +0300 Subject: [PATCH 1/6] Fix WebView crash (cherry picked from commit fa37c72923d10d20a5ff7617b943c5667dd86d06) --- .../kotlin/org/koitharu/kotatsu/browser/BrowserClient.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserClient.kt b/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserClient.kt index 053f1074f..e13231611 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserClient.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/browser/BrowserClient.kt @@ -2,11 +2,15 @@ package org.koitharu.kotatsu.browser import android.graphics.Bitmap import android.webkit.WebView -import androidx.webkit.WebViewClientCompat +import android.webkit.WebViewClient open class BrowserClient( private val callback: BrowserCallback -) : WebViewClientCompat() { +) : WebViewClient() { + + /** + * https://stackoverflow.com/questions/57414530/illegalstateexception-reasonphrase-cant-be-empty-with-android-webview + */ override fun onPageFinished(webView: WebView, url: String) { super.onPageFinished(webView, url) From f6aad3355a26ece8aa531ad7e8812f214bdb5042 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 24 May 2025 21:13:33 +0300 Subject: [PATCH 2/6] Update parsers (cherry picked from commit 19d0fe97a0c486ed23f941ca83c3eb2e7be33c42) --- .../ContinuationResumeWebViewClient.kt | 16 ++++++++++++++ .../core/parser/MangaLoaderContextImpl.kt | 15 +++++++++++++ .../koitharu/kotatsu/core/util/ext/Android.kt | 1 + .../sources/SourceSettingsFragment.kt | 5 ++++- .../sources/SourceSettingsViewModel.kt | 3 +++ .../sources/auth/SourceAuthActivity.kt | 22 +++++++++++++++---- app/src/main/res/xml/pref_source_parser.xml | 1 + gradle/libs.versions.toml | 2 +- 8 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/network/webview/ContinuationResumeWebViewClient.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/webview/ContinuationResumeWebViewClient.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/webview/ContinuationResumeWebViewClient.kt new file mode 100644 index 000000000..c7d3a2794 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/webview/ContinuationResumeWebViewClient.kt @@ -0,0 +1,16 @@ +package org.koitharu.kotatsu.core.network.webview + +import android.webkit.WebView +import android.webkit.WebViewClient +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume + +class ContinuationResumeWebViewClient( + private val continuation: Continuation, +) : WebViewClient() { + + override fun onPageFinished(view: WebView?, url: String?) { + view?.webViewClient = WebViewClient() // reset to default + continuation.resume(Unit) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt index 9d07a1c47..aaa717ac1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt @@ -18,6 +18,7 @@ import okio.Buffer import org.koitharu.kotatsu.core.image.BitmapDecoderCompat import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar +import org.koitharu.kotatsu.core.network.webview.ContinuationResumeWebViewClient import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.util.ext.configureForParser import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug @@ -49,6 +50,7 @@ class MangaLoaderContextImpl @Inject constructor( private var webViewCached: WeakReference? = null private val webViewUserAgent by lazy { obtainWebViewUserAgent() } + @Deprecated("Provide a base url") @SuppressLint("SetJavaScriptEnabled") override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main.immediate) { val webView = obtainWebView() @@ -59,6 +61,19 @@ class MangaLoaderContextImpl @Inject constructor( } } + override suspend fun evaluateJs(baseUrl: String, script: String): String? = withContext(Dispatchers.Main.immediate) { + val webView = obtainWebView() + suspendCoroutine { cont -> + webView.webViewClient = ContinuationResumeWebViewClient(cont) + webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null) + } + suspendCoroutine { cont -> + webView.evaluateJavascript(script) { result -> + cont.resume(result?.takeUnless { it == "null" }) + } + } + } + override fun getDefaultUserAgent(): String = webViewUserAgent override fun getConfig(source: MangaSource): MangaSourceConfig { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt index cfd5c5967..e8ce3eed1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt @@ -215,6 +215,7 @@ fun WebView.configureForParser(userAgentOverride: String?) = with(settings) { WebViewCompat.setAudioMuted(this@configureForParser, true) } databaseEnabled = true + allowContentAccess = false if (userAgentOverride != null) { userAgentString = userAgentOverride } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt index 68d5675d7..7bf90f703 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsFragment.kt @@ -6,6 +6,7 @@ import androidx.fragment.app.viewModels import androidx.preference.Preference import androidx.preference.SwitchPreferenceCompat import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.filterNotNull import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.model.getTitle @@ -49,13 +50,15 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc findPreference(KEY_AUTH)?.run { val authProvider = (viewModel.repository as? ParserMangaRepository)?.getAuthProvider() isVisible = authProvider != null - isEnabled = authProvider?.isAuthorized == false } findPreference(SourceSettings.KEY_SLOWDOWN)?.isVisible = isValidSource } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + viewModel.isAuthorized.filterNotNull().observe(viewLifecycleOwner) { isAuthorized -> + findPreference(KEY_AUTH)?.isEnabled = !isAuthorized + } viewModel.username.observe(viewLifecycleOwner) { username -> findPreference(KEY_AUTH)?.summary = username?.let { getString(R.string.logged_in_as, it) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt index 595e81dee..bcd57bc61 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/SourceSettingsViewModel.kt @@ -38,6 +38,7 @@ class SourceSettingsViewModel @Inject constructor( val onActionDone = MutableEventFlow() val username = MutableStateFlow(null) + val isAuthorized = MutableStateFlow(null) val browserUrl = MutableStateFlow(null) val isEnabled = mangaSourcesRepository.observeIsEnabled(source) private var usernameLoadJob: Job? = null @@ -103,6 +104,8 @@ class SourceSettingsViewModel @Inject constructor( launchLoadingJob(Dispatchers.Default) { try { username.value = null + isAuthorized.value = null + isAuthorized.value = authProvider?.isAuthorized() username.value = authProvider?.getUsername() } catch (_: AuthRequiredException) { } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt index a119b0caa..56815f0d0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/sources/auth/SourceAuthActivity.kt @@ -9,6 +9,7 @@ import androidx.activity.result.contract.ActivityResultContract import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import org.koitharu.kotatsu.R import org.koitharu.kotatsu.browser.BaseBrowserActivity @@ -20,12 +21,15 @@ import org.koitharu.kotatsu.core.parser.ParserMangaRepository import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.parsers.MangaParserAuthProvider import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.util.runCatchingCancellable @AndroidEntryPoint class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback { private lateinit var authProvider: MangaParserAuthProvider + private var authCheckJob: Job? = null + override fun onCreate2(savedInstanceState: Bundle?, source: MangaSource, repository: ParserMangaRepository?) { if (repository == null) { finishAfterTransition() @@ -72,10 +76,20 @@ class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback { override fun onLoadingStateChanged(isLoading: Boolean) { super.onLoadingStateChanged(isLoading) - if (!isLoading && authProvider.isAuthorized) { - Toast.makeText(this, R.string.auth_complete, Toast.LENGTH_SHORT).show() - setResult(RESULT_OK) - finishAfterTransition() + if (isLoading) { + return + } + val prevJob = authCheckJob + authCheckJob = lifecycleScope.launch { + prevJob?.join() + val isAuthorized = runCatchingCancellable { + authProvider.isAuthorized() + }.getOrDefault(false) + if (isAuthorized) { + Toast.makeText(this@SourceAuthActivity, R.string.auth_complete, Toast.LENGTH_SHORT).show() + setResult(RESULT_OK) + finishAfterTransition() + } } } diff --git a/app/src/main/res/xml/pref_source_parser.xml b/app/src/main/res/xml/pref_source_parser.xml index a50fd3354..36c592b69 100644 --- a/app/src/main/res/xml/pref_source_parser.xml +++ b/app/src/main/res/xml/pref_source_parser.xml @@ -4,6 +4,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> Date: Sun, 25 May 2025 10:05:10 +0300 Subject: [PATCH 3/6] Fix race condition while js evaluation (cherry picked from commit 41d7fd1b8607b03ea6b3c9a5c01138ab2979eb47) --- .../core/parser/MangaLoaderContextImpl.kt | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt index aaa717ac1..548ce2d8d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/parser/MangaLoaderContextImpl.kt @@ -9,7 +9,10 @@ import androidx.core.os.LocaleListCompat import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Response @@ -34,6 +37,7 @@ import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.util.map import java.lang.ref.WeakReference import java.util.Locale +import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton import kotlin.coroutines.EmptyCoroutineContext @@ -49,27 +53,28 @@ class MangaLoaderContextImpl @Inject constructor( private var webViewCached: WeakReference? = null private val webViewUserAgent by lazy { obtainWebViewUserAgent() } + private val jsMutex = Mutex() + private val jsTimeout = TimeUnit.SECONDS.toMillis(4) @Deprecated("Provide a base url") @SuppressLint("SetJavaScriptEnabled") - override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main.immediate) { - val webView = obtainWebView() - suspendCoroutine { cont -> - webView.evaluateJavascript(script) { result -> - cont.resume(result?.takeUnless { it == "null" }) - } - } - } + override suspend fun evaluateJs(script: String): String? = evaluateJs("", script) - override suspend fun evaluateJs(baseUrl: String, script: String): String? = withContext(Dispatchers.Main.immediate) { - val webView = obtainWebView() - suspendCoroutine { cont -> - webView.webViewClient = ContinuationResumeWebViewClient(cont) - webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null) - } - suspendCoroutine { cont -> - webView.evaluateJavascript(script) { result -> - cont.resume(result?.takeUnless { it == "null" }) + override suspend fun evaluateJs(baseUrl: String, script: String): String? = withTimeout(jsTimeout) { + jsMutex.withLock { + withContext(Dispatchers.Main.immediate) { + val webView = obtainWebView() + if (baseUrl.isNotEmpty()) { + suspendCoroutine { cont -> + webView.webViewClient = ContinuationResumeWebViewClient(cont) + webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null) + } + } + suspendCoroutine { cont -> + webView.evaluateJavascript(script) { result -> + cont.resume(result?.takeUnless { it == "null" }) + } + } } } } From f79960668892531c4575e17c5bc746c813d73bfd Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 25 May 2025 19:54:56 +0300 Subject: [PATCH 4/6] Fix snackbar positioning (cherry picked from commit b1497f2ace1bcba29ce1acba0ca43ebd647e12fe) --- .../exceptions/resolve/SnackbarErrorObserver.kt | 6 ++++-- .../core/ui/util/ReversibleActionObserver.kt | 9 ++++++--- .../kotatsu/details/ui/DetailsActivity.kt | 16 ++++++++++++---- .../details/ui/pager/ChaptersPagesSheet.kt | 2 +- .../kotatsu/main/ui/owners/BottomSheetOwner.kt | 8 ++++++++ 5 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/main/ui/owners/BottomSheetOwner.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt index bec64d18c..922f8f0ee 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt @@ -8,6 +8,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner +import org.koitharu.kotatsu.main.ui.owners.BottomSheetOwner import org.koitharu.kotatsu.parsers.exception.ParseException class SnackbarErrorObserver( @@ -24,8 +25,9 @@ class SnackbarErrorObserver( override suspend fun emit(value: Throwable) { val snackbar = Snackbar.make(host, value.getDisplayMessage(host.context.resources), Snackbar.LENGTH_SHORT) - if (activity is BottomNavOwner) { - snackbar.anchorView = activity.bottomNav + when (activity) { + is BottomNavOwner -> snackbar.anchorView = activity.bottomNav + is BottomSheetOwner -> snackbar.anchorView = activity.bottomSheet } if (canResolve(value)) { snackbar.setAction(ExceptionResolver.getResolveStringId(value)) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt index 8d94173d9..8757c821c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/util/ReversibleActionObserver.kt @@ -4,18 +4,21 @@ import android.view.View import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.flow.FlowCollector import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.util.ext.findActivity +import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner +import org.koitharu.kotatsu.main.ui.owners.BottomSheetOwner class ReversibleActionObserver( private val snackbarHost: View, - private val snackbarAnchor: View? = null, ) : FlowCollector { override suspend fun emit(value: ReversibleAction) { val handle = value.handle val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG val snackbar = Snackbar.make(snackbarHost, value.stringResId, length) - if (snackbarAnchor?.isShown == true) { - snackbar.anchorView = snackbarAnchor + when (val activity = snackbarHost.context.findActivity()) { + is BottomNavOwner -> snackbar.anchorView = activity.bottomNav + is BottomSheetOwner -> snackbar.anchorView = activity.bottomSheet } if (handle != null) { snackbar.setAction(R.string.undo) { handle.reverseAsync() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 02980f9c4..9416b524c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -104,6 +104,7 @@ import org.koitharu.kotatsu.list.ui.adapter.mangaGridItemAD import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.list.ui.size.StaticItemSizeResolver +import org.koitharu.kotatsu.main.ui.owners.BottomSheetOwner import org.koitharu.kotatsu.parsers.model.ContentRating import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaTag @@ -119,9 +120,13 @@ import com.google.android.material.R as materialR class DetailsActivity : BaseActivity(), View.OnClickListener, - View.OnLayoutChangeListener, ViewTreeObserver.OnDrawListener, - ChipsView.OnChipClickListener, OnListItemClickListener, - SwipeRefreshLayout.OnRefreshListener, AuthorSpan.OnAuthorClickListener { + View.OnLayoutChangeListener, + ViewTreeObserver.OnDrawListener, + ChipsView.OnChipClickListener, + OnListItemClickListener, + SwipeRefreshLayout.OnRefreshListener, + AuthorSpan.OnAuthorClickListener, + BottomSheetOwner { @Inject lateinit var shortcutManager: AppShortcutManager @@ -133,6 +138,9 @@ class DetailsActivity : private lateinit var menuProvider: DetailsMenuProvider private lateinit var infoBinding: LayoutDetailsTableBinding + override val bottomSheet: View? + get() = viewBinding.containerBottomSheet + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityDetailsBinding.inflate(layoutInflater)) @@ -172,7 +180,7 @@ class DetailsActivity : .observeEvent(this, DetailsErrorObserver(this, viewModel, exceptionResolver)) viewModel.onActionDone .filterNot { appRouter.isChapterPagesSheetShown() } - .observeEvent(this, ReversibleActionObserver(viewBinding.scrollView, null)) + .observeEvent(this, ReversibleActionObserver(viewBinding.scrollView)) combine(viewModel.historyInfo, viewModel.isLoading, ::Pair).observe(this) { onHistoryChanged(it.first, it.second) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt index a1f7f22b7..c49071301 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesSheet.kt @@ -89,7 +89,7 @@ class ChaptersPagesSheet : BaseAdaptiveSheet(), viewModel.newChaptersCount.observe(viewLifecycleOwner, ::onNewChaptersChanged) if (dialog != null) { viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.pager, this)) - viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.pager, null)) + viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.pager)) viewModel.onDownloadStarted.observeEvent(viewLifecycleOwner, DownloadStartedObserver(binding.pager)) } else { PeekHeightController(arrayOf(binding.headerBar, binding.toolbar)).attach() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/owners/BottomSheetOwner.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/owners/BottomSheetOwner.kt new file mode 100644 index 000000000..a687cb8d1 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/owners/BottomSheetOwner.kt @@ -0,0 +1,8 @@ +package org.koitharu.kotatsu.main.ui.owners + +import android.view.View + +interface BottomSheetOwner { + + val bottomSheet: View? +} From 8d9129daafdb72bfe565a09a4ab6e9de4eedf0d7 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 26 May 2025 18:25:17 +0300 Subject: [PATCH 5/6] Fix serivce starting crash on startup (cherry picked from commit 157d5e6c05d54f2e3dad5c0038df6ffe2bbddf22) --- .../main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index 3f94c1009..bd5a7d789 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -380,9 +380,9 @@ class MainActivity : BaseActivity(), AppBarOwner, BottomNav withResumed { MangaPrefetchService.prefetchLast(this@MainActivity) requestNotificationsPermission() + startService(Intent(this@MainActivity, LocalIndexUpdateService::class.java)) + startService(Intent(this@MainActivity, PeriodicalBackupService::class.java)) } - startService(Intent(this@MainActivity, LocalIndexUpdateService::class.java)) - startService(Intent(this@MainActivity, PeriodicalBackupService::class.java)) } } From 0ed2232ac2377c972cbdba7f0d82d007331dfd40 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 27 May 2025 17:03:14 +0300 Subject: [PATCH 6/6] Update parsers --- app/build.gradle | 4 ++-- gradle/libs.versions.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index fcec9b620..c106e8db3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,8 +19,8 @@ android { applicationId 'org.koitharu.kotatsu' minSdk = 21 targetSdk = 35 - versionCode = 1013 - versionName = '8.1.7' + versionCode = 1014 + versionName = '8.1.8' generatedDensities = [] testInstrumentationRunner 'org.koitharu.kotatsu.HiltTestRunner' ksp { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9f967213a..5c6fb22ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ material = "1.13.0-alpha12" moshi = "1.15.2" okhttp = "4.12.0" okio = "3.11.0" -parsers = "7b1a0b8d0d" +parsers = "6bf377a654" preference = "1.2.1" recyclerview = "1.4.0" room = "2.6.1"